<!DOCTYPE html>
<html>
<head><meta name="generator" content="Hexo 3.8.0">
    

    
<!-- Tencent Speed -->
<script>var _speedMark = new Date()</script>
<!-- End Tencent Speed -->
<!-- Tencent Analysis -->
<script async src="//tajs.qq.com/stats?sId=false."></script>
<!-- End Tencent Analysis -->


    



    <meta charset="utf-8">
    
    
    <meta name="google-site-verification" content="CUm1VNyzpZuuHWWTWLOVfbkoMiz6Q9ccqUY5rMp9vcI">

    
    
    <title>JUC和JVM | Edward</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    
    <meta name="theme-color" content="#3F51B5">
    
    
    <meta name="keywords" content="java">
    <meta name="description" content="jdk&amp;amp;jvm&amp;amp;juc(部分图源:JavaGuide) java基础知识 Java常见基础知识点 面向对象和面向过程的区别 OracleJdk与OpenJdk的区别 Java与C  的异同 JVM,JDK和JRE的区别 Java语言的特点 面向对象的特征 重载和重写的区别 接口与抽象类的区别 Object类的方法有哪些? 静态属性方法和成员属性方法区别 子类属性与父类属性初始化">
<meta name="keywords" content="java">
<meta property="og:type" content="article">
<meta property="og:title" content="JUC和JVM">
<meta property="og:url" content="http://springcloud.xn--ses554g/2020/04/07/jdk_jvm_juc-learning/index.html">
<meta property="og:site_name" content="Edward">
<meta property="og:description" content="jdk&amp;amp;jvm&amp;amp;juc(部分图源:JavaGuide) java基础知识 Java常见基础知识点 面向对象和面向过程的区别 OracleJdk与OpenJdk的区别 Java与C  的异同 JVM,JDK和JRE的区别 Java语言的特点 面向对象的特征 重载和重写的区别 接口与抽象类的区别 Object类的方法有哪些? 静态属性方法和成员属性方法区别 子类属性与父类属性初始化">
<meta property="og:locale" content="default">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/对象在内存中的布局.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/对象头的markword组成1.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/对象头的markword组成2.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/对象头的markword组成3.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/对象头的markword组成4.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/jol工具查看对象内存布局1.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/jol工具查看对象内存布局2.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/hashcode方法源码.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/synchronized底层原理1.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/synchronized底层原理2.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/synchronized底层原理3.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/synchronized底层原理4.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/偏向锁实现.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/轻量级锁实现.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/死锁.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/Java内存模型.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/跳表.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/用户态与内核态.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/BIO原理.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/NIO原理.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/多路复用IO原理.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/信号驱动IO原理.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/异步IO原理.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/jdk8之前的JVM内存分区.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/jdk8之后的jvm内存分区.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/JVM程序计数器.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/Java虚拟机栈.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/局部变量表.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/Class文件常量池.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/堆内存分区.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/Class文件结构1.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/Class文件结构2.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/类的生命周期.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/ClassLoader部分注释.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/类卸载.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/双亲委派机制.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/Class文件常量池.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/可达性算法.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/复制算法.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/标记-清除算法.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/标记-整理算法.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/垃圾回收器分类.png">
<meta property="og:image" content="http://springcloud.xn--ses554g/img/G1收集器Region.png">
<meta property="og:updated_time" content="2020-04-13T09:28:05.045Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="JUC和JVM">
<meta name="twitter:description" content="jdk&amp;amp;jvm&amp;amp;juc(部分图源:JavaGuide) java基础知识 Java常见基础知识点 面向对象和面向过程的区别 OracleJdk与OpenJdk的区别 Java与C  的异同 JVM,JDK和JRE的区别 Java语言的特点 面向对象的特征 重载和重写的区别 接口与抽象类的区别 Object类的方法有哪些? 静态属性方法和成员属性方法区别 子类属性与父类属性初始化">
<meta name="twitter:image" content="http://springcloud.xn--ses554g/img/对象在内存中的布局.png">
    
        <link rel="alternate" type="application/atom+xml" title="Edward" href="/atom.xml">
    
    <link rel="shortcut icon" href="/img/favicon.ico">
    <link rel="stylesheet" href="//unpkg.com/hexo-theme-material-indigo@latest/css/style.css">
    <script>window.lazyScripts=[]</script>

    <!-- custom head -->
    

    <script>
        (function(){
            var bp = document.createElement('script');
            var curProtocol = window.location.protocol.split(':')[0];
            if (curProtocol === 'https'){
                bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
            }
            else{
                bp.src = 'http://push.zhanzhang.baidu.com/push.js';
            }
            var s = document.getElementsByTagName("script")[0];
            s.parentNode.insertBefore(bp, s);
        })();
    </script>

</head>

<body>
    <div id="loading" class="active"></div>

    <aside id="menu">
  <div class="inner flex-row-vertical">
    <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menu-off">
        <i class="icon icon-lg icon-close"></i>
    </a>
    <div class="brand-wrap" style="background-image:url(/img/brand.jpg)">
      <div class="brand" style="padding-top: 30%;">
        <a href="/" class="avatar waves-effect waves-circle waves-light">
          <img src="/img/123.png">
        </a>
        <hgroup class="introduce">
          <h5 class="nickname">Edward</h5>
          <a href="mailto:zqmssbd@qq.com" title="zqmssbd@qq.com" class="mail">zqmssbd@qq.com</a>
        </hgroup>
      </div>
    </div>
    <div class="scroll-wrap flex-col">
      <ul class="nav">
        
            <li class="waves-block waves-effect">
              <a href="/">
                <i class="icon icon-lg icon-home"></i>
                主页
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="/archives">
                <i class="icon icon-lg icon-archives"></i>
                Archives
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="/tags">
                <i class="icon icon-lg icon-tags"></i>
                Tags
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="/categories">
                <i class="icon icon-lg icon-th-list"></i>
                Categories
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="https://github.com/zqmssbd" target="_blank">
                <i class="icon icon-lg icon-github"></i>
                Github
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="https://weibo.com/5333276247" target="_blank">
                <i class="icon icon-lg icon-weibo"></i>
                Weibo
              </a>
            </li>
          
            <li class="waves-block waves-effect">
              <a href="https://gitee.com/Edward-Z" target="_blank">
                <i class="icon icon-lg icon-link"></i>
                码云
              </a>
            </li>
          
      </ul>
        <div id="tp-weather-widget"></div>
        <script>
            (function(a,h,g,f,e,d,c,b){b=function(){d=h.createElement(g);c=h.getElementsByTagName(g)[0];d.src=e;d.charset="utf-8";d.async=1;c.parentNode.insertBefore(d,c)};a["SeniverseWeatherWidgetObject"]=f;a[f]||(a[f]=function(){(a[f].q=a[f].q||[]).push(arguments)});a[f].l=+new Date();if(a.attachEvent){a.attachEvent("onload",b)}else{a.addEventListener("load",b,false)}}(window,document,"script","SeniverseWeatherWidget","//cdn.sencdn.com/widget2/static/js/bundle.js?t="+parseInt((new Date().getTime() / 100000000).toString(),10)));
            window.SeniverseWeatherWidget('show', {
                flavor: "bubble",
                location: "WT3Q0FW9ZJ3Q",
                geolocation: true,
                language: "zh-Hans",
                unit: "c",
                theme: "auto",
                token: "74eabe8a-0b6b-4a56-86ac-c773a4d98218",
                hover: "enabled",
                container: "tp-weather-widget"
            })
        </script>

        <link rel="stylesheet" href="/css/APlayer.css">
        <div id="player" class="aplayer aplayer-withlist aplayer-fixed" data-id="3895885" data-server="netease" data-type="playlist" data-order="random" data-fixed="true" data-listfolded="false" data-theme="#2D8CF0"></div>
        <script src="/js/APlayer.min.js"></script>
        <script src="/js/Meting.min.js"></script>

        


        

    </div>
  </div>
</aside>

    <main id="main">
        <header class="top-header" id="header">
    <div class="flex-row">
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light on" id="menu-toggle">
          <i class="icon icon-lg icon-navicon"></i>
        </a>
        <div class="flex-col header-title ellipsis">JUC和JVM</div>
        
        <div class="search-wrap" id="search-wrap">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="back">
                <i class="icon icon-lg icon-chevron-left"></i>
            </a>
            <input type="text" id="key" class="search-input" autocomplete="off" placeholder="输入感兴趣的关键字">
            <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="search">
                <i class="icon icon-lg icon-search"></i>
            </a>
        </div>
        
        
        <a href="javascript:;" class="header-icon waves-effect waves-circle waves-light" id="menuShare">
            <i class="icon icon-lg icon-share-alt"></i>
        </a>
        
    </div>
</header>
<header class="content-header post-header">

    <div class="container fade-scale">
        <h1 class="title">JUC和JVM</h1>
        <h5 class="title">你真的还不够，不够勤奋和努力。</h5>
        <h5 class="subtitle">
            
                <time datetime="2020-04-07T08:44:22.000Z" itemprop="datePublished" class="page-time">
  2020-04-07
</time>


	<ul class="article-category-list"><li class="article-category-list-item"><a class="article-category-list-link" href="/categories/JUC/">JUC</a><ul class="article-category-list-child"><li class="article-category-list-item"><a class="article-category-list-link" href="/categories/JUC/JVM/">JVM</a></li></ul></li></ul>

            
        </h5>
    </div>

    

    <script>
        (function(){
            var bp = document.createElement('script');
            var curProtocol = window.location.protocol.split(':')[0];
            if (curProtocol === 'https'){
                bp.src = 'https://zz.bdstatic.com/linksubmit/push.js';
            }
            else{
                bp.src = 'http://push.zhanzhang.baidu.com/push.js';
            }
            var s = document.getElementsByTagName("script")[0];
            s.parentNode.insertBefore(bp, s);
        })();
    </script>
</header>


<div class="container body-wrap">
    
    <aside class="post-widget">
        <nav class="post-toc-wrap post-toc-shrink" id="post-toc">
            <h4>TOC</h4>
            <ol class="post-toc"><li class="post-toc-item post-toc-level-1"><a class="post-toc-link" href="#jdk-amp-jvm-amp-juc-部分图源-JavaGuide"><span class="post-toc-number">1.</span> <span class="post-toc-text">jdk&amp;jvm&amp;juc(部分图源:JavaGuide)</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#java基础知识"><span class="post-toc-number">1.1.</span> <span class="post-toc-text">java基础知识</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#Java常见基础知识点"><span class="post-toc-number">1.1.1.</span> <span class="post-toc-text">Java常见基础知识点</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#面向对象和面向过程的区别"><span class="post-toc-number">1.1.1.1.</span> <span class="post-toc-text">面向对象和面向过程的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#OracleJdk与OpenJdk的区别"><span class="post-toc-number">1.1.1.2.</span> <span class="post-toc-text">OracleJdk与OpenJdk的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Java与C-的异同"><span class="post-toc-number">1.1.1.3.</span> <span class="post-toc-text">Java与C++的异同</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#JVM-JDK和JRE的区别"><span class="post-toc-number">1.1.1.4.</span> <span class="post-toc-text">JVM,JDK和JRE的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Java语言的特点"><span class="post-toc-number">1.1.1.5.</span> <span class="post-toc-text">Java语言的特点</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#面向对象的特征"><span class="post-toc-number">1.1.1.6.</span> <span class="post-toc-text">面向对象的特征</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#重载和重写的区别"><span class="post-toc-number">1.1.1.7.</span> <span class="post-toc-text">重载和重写的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#接口与抽象类的区别"><span class="post-toc-number">1.1.1.8.</span> <span class="post-toc-text">接口与抽象类的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Object类的方法有哪些"><span class="post-toc-number">1.1.1.9.</span> <span class="post-toc-text">Object类的方法有哪些?</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#静态属性方法和成员属性方法区别"><span class="post-toc-number">1.1.1.10.</span> <span class="post-toc-text">静态属性方法和成员属性方法区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#子类属性与父类属性初始化顺序"><span class="post-toc-number">1.1.1.11.</span> <span class="post-toc-text">子类属性与父类属性初始化顺序</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#自动拆箱和装箱"><span class="post-toc-number">1.1.1.12.</span> <span class="post-toc-text">自动拆箱和装箱</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#String为什么不可变"><span class="post-toc-number">1.1.1.13.</span> <span class="post-toc-text">String为什么不可变?</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#final关键字的作用"><span class="post-toc-number">1.1.1.14.</span> <span class="post-toc-text">final关键字的作用</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#StringBuilder和StringBuffer区别"><span class="post-toc-number">1.1.1.15.</span> <span class="post-toc-text">StringBuilder和StringBuffer区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#equals知识点"><span class="post-toc-number">1.1.1.16.</span> <span class="post-toc-text">equals知识点</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#深拷贝与浅拷贝"><span class="post-toc-number">1.1.1.17.</span> <span class="post-toc-text">深拷贝与浅拷贝</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#IO流分类"><span class="post-toc-number">1.1.1.18.</span> <span class="post-toc-text">IO流分类</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#使用字节流还是字符流"><span class="post-toc-number">1.1.1.19.</span> <span class="post-toc-text">使用字节流还是字符流?</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#BigDecimal"><span class="post-toc-number">1.1.1.20.</span> <span class="post-toc-text">BigDecimal</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Java异常体系结构"><span class="post-toc-number">1.1.1.21.</span> <span class="post-toc-text">Java异常体系结构</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Comparable和Comparator"><span class="post-toc-number">1.1.1.22.</span> <span class="post-toc-text">Comparable和Comparator</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#为什么要慎用-Arrays-asList"><span class="post-toc-number">1.1.1.23.</span> <span class="post-toc-text">为什么要慎用 Arrays.asList()?</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Java中引用的类型"><span class="post-toc-number">1.1.1.24.</span> <span class="post-toc-text">Java中引用的类型</span></a></li></ol></li></ol></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#对象在内存中的布局-64位"><span class="post-toc-number">1.2.</span> <span class="post-toc-text">对象在内存中的布局(64位)</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#对象头"><span class="post-toc-number">1.2.1.</span> <span class="post-toc-text">对象头</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#markword和metadata"><span class="post-toc-number">1.2.1.1.</span> <span class="post-toc-text">markword和metadata</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#实例数据"><span class="post-toc-number">1.2.1.2.</span> <span class="post-toc-text">实例数据</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#对齐填充"><span class="post-toc-number">1.2.1.3.</span> <span class="post-toc-text">对齐填充</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#jol工具查看对象布局"><span class="post-toc-number">1.2.2.</span> <span class="post-toc-text">jol工具查看对象布局</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#查看对象内存布局"><span class="post-toc-number">1.2.2.1.</span> <span class="post-toc-text">查看对象内存布局</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#hashcode"><span class="post-toc-number">1.2.2.2.</span> <span class="post-toc-text">hashcode</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#对象的hashcode返回的是对象的内存地址吗"><span class="post-toc-number">1.2.2.3.</span> <span class="post-toc-text">对象的hashcode返回的是对象的内存地址吗?</span></a></li></ol></li></ol></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#线程并发-JUC-AQS-CAS"><span class="post-toc-number">1.3.</span> <span class="post-toc-text">线程并发(JUC,AQS,CAS)</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#多线程"><span class="post-toc-number">1.3.1.</span> <span class="post-toc-text">多线程</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#进程和线程"><span class="post-toc-number">1.3.1.1.</span> <span class="post-toc-text">进程和线程</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#并发和并行"><span class="post-toc-number">1.3.1.2.</span> <span class="post-toc-text">并发和并行</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#多线程的利弊"><span class="post-toc-number">1.3.1.3.</span> <span class="post-toc-text">多线程的利弊</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#什么是上下文切换"><span class="post-toc-number">1.3.1.4.</span> <span class="post-toc-text">什么是上下文切换?</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#线程的优先级"><span class="post-toc-number">1.3.1.5.</span> <span class="post-toc-text">线程的优先级</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#线程的几种状态"><span class="post-toc-number">1.3.1.6.</span> <span class="post-toc-text">线程的几种状态</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#sleep方法和wait方法"><span class="post-toc-number">1.3.1.7.</span> <span class="post-toc-text">sleep方法和wait方法</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#stop-suspend-resume等方法为什么会被遗弃"><span class="post-toc-number">1.3.1.8.</span> <span class="post-toc-text">stop,suspend,resume等方法为什么会被遗弃</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#interrupt-interrupted-isInterrupted方法区别"><span class="post-toc-number">1.3.1.9.</span> <span class="post-toc-text">interrupt,interrupted,isInterrupted方法区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#join方法"><span class="post-toc-number">1.3.1.10.</span> <span class="post-toc-text">join方法</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#yield方法"><span class="post-toc-number">1.3.1.11.</span> <span class="post-toc-text">yield方法</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#并发"><span class="post-toc-number">1.3.2.</span> <span class="post-toc-text">并发</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#synchronized"><span class="post-toc-number">1.3.2.1.</span> <span class="post-toc-text">synchronized</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#synchronized底层原理"><span class="post-toc-number">1.3.2.2.</span> <span class="post-toc-text">synchronized底层原理</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#synchronized-使用方法"><span class="post-toc-number">1.3.2.3.</span> <span class="post-toc-text">synchronized 使用方法</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Synchronized和ReentrantLock的区别"><span class="post-toc-number">1.3.2.4.</span> <span class="post-toc-text">Synchronized和ReentrantLock的区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#乐观锁"><span class="post-toc-number">1.3.2.5.</span> <span class="post-toc-text">乐观锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#悲观锁"><span class="post-toc-number">1.3.2.6.</span> <span class="post-toc-text">悲观锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#独占锁"><span class="post-toc-number">1.3.2.7.</span> <span class="post-toc-text">独占锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#共享锁"><span class="post-toc-number">1.3.2.8.</span> <span class="post-toc-text">共享锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#公平锁"><span class="post-toc-number">1.3.2.9.</span> <span class="post-toc-text">公平锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#非公平锁"><span class="post-toc-number">1.3.2.10.</span> <span class="post-toc-text">非公平锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#可重入锁-递归锁"><span class="post-toc-number">1.3.2.11.</span> <span class="post-toc-text">可重入锁(递归锁)</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#偏向锁"><span class="post-toc-number">1.3.2.12.</span> <span class="post-toc-text">偏向锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#轻量级锁"><span class="post-toc-number">1.3.2.13.</span> <span class="post-toc-text">轻量级锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#自旋锁"><span class="post-toc-number">1.3.2.14.</span> <span class="post-toc-text">自旋锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#自适应自旋锁"><span class="post-toc-number">1.3.2.15.</span> <span class="post-toc-text">自适应自旋锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#锁消除"><span class="post-toc-number">1.3.2.16.</span> <span class="post-toc-text">锁消除</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#死锁"><span class="post-toc-number">1.3.2.17.</span> <span class="post-toc-text">死锁</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#如何避免死锁"><span class="post-toc-number">1.3.2.18.</span> <span class="post-toc-text">如何避免死锁?</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#volatile"><span class="post-toc-number">1.3.3.</span> <span class="post-toc-text">volatile</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#volatile保证内存的可见性"><span class="post-toc-number">1.3.3.1.</span> <span class="post-toc-text">volatile保证内存的可见性</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#volatile禁止指令重排序"><span class="post-toc-number">1.3.3.2.</span> <span class="post-toc-text">volatile禁止指令重排序</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#volatile如何禁止指令重排序的"><span class="post-toc-number">1.3.3.3.</span> <span class="post-toc-text">volatile如何禁止指令重排序的?</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#volatile不保证原子性"><span class="post-toc-number">1.3.3.4.</span> <span class="post-toc-text">volatile不保证原子性</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#CAS"><span class="post-toc-number">1.3.4.</span> <span class="post-toc-text">CAS</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#CAS在JAVA中的底层实现-Atomic原子类实现"><span class="post-toc-number">1.3.4.1.</span> <span class="post-toc-text">CAS在JAVA中的底层实现(Atomic原子类实现)</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#CAS的缺点"><span class="post-toc-number">1.3.4.2.</span> <span class="post-toc-text">CAS的缺点</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#解决ABA问题"><span class="post-toc-number">1.3.4.3.</span> <span class="post-toc-text">解决ABA问题</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#ThreadLocal"><span class="post-toc-number">1.3.4.4.</span> <span class="post-toc-text">ThreadLocal</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#ThreadLocal引发的内存泄露"><span class="post-toc-number">1.3.4.5.</span> <span class="post-toc-text">ThreadLocal引发的内存泄露</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#线程池的好处"><span class="post-toc-number">1.3.4.6.</span> <span class="post-toc-text">线程池的好处</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#线程池构造参数"><span class="post-toc-number">1.3.4.7.</span> <span class="post-toc-text">线程池构造参数</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#阿里巴巴开发者手册不建议开发者使用Executors创建线程池"><span class="post-toc-number">1.3.4.8.</span> <span class="post-toc-text">阿里巴巴开发者手册不建议开发者使用Executors创建线程池</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#AQS-AbstractQueuedSynchronizer"><span class="post-toc-number">1.3.5.</span> <span class="post-toc-text">AQS(AbstractQueuedSynchronizer)</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#AQS概述"><span class="post-toc-number">1.3.5.1.</span> <span class="post-toc-text">AQS概述</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#AQS的两种共享资源的访问方式"><span class="post-toc-number">1.3.5.2.</span> <span class="post-toc-text">AQS的两种共享资源的访问方式</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#lock-tryLock和lockInterruptibly区别"><span class="post-toc-number">1.3.5.3.</span> <span class="post-toc-text">lock,tryLock和lockInterruptibly区别</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#CountDownLatch"><span class="post-toc-number">1.3.5.4.</span> <span class="post-toc-text">CountDownLatch</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Semaphore"><span class="post-toc-number">1.3.5.5.</span> <span class="post-toc-text">Semaphore</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#CycliBarrier"><span class="post-toc-number">1.3.5.6.</span> <span class="post-toc-text">CycliBarrier</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#ReentrantReadWriteLock如何区分读写锁的"><span class="post-toc-number">1.3.5.7.</span> <span class="post-toc-text">ReentrantReadWriteLock如何区分读写锁的?</span></a></li></ol></li></ol></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#Java集合"><span class="post-toc-number">1.4.</span> <span class="post-toc-text">Java集合</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#HashMap的特点"><span class="post-toc-number">1.4.0.1.</span> <span class="post-toc-text">HashMap的特点</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#HashMap的长度-容量-为什么要设计成2的幂？"><span class="post-toc-number">1.4.0.2.</span> <span class="post-toc-text">HashMap的长度(容量)为什么要设计成2的幂？</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#HashTable的特点"><span class="post-toc-number">1.4.0.3.</span> <span class="post-toc-text">HashTable的特点</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#TreeMap"><span class="post-toc-number">1.4.0.4.</span> <span class="post-toc-text">TreeMap</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#ArrayList的特点"><span class="post-toc-number">1.4.0.5.</span> <span class="post-toc-text">ArrayList的特点</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Vector的特点"><span class="post-toc-number">1.4.0.6.</span> <span class="post-toc-text">Vector的特点</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#LinkedList的特点"><span class="post-toc-number">1.4.0.7.</span> <span class="post-toc-text">LinkedList的特点</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Set"><span class="post-toc-number">1.4.0.8.</span> <span class="post-toc-text">Set</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#ConcurrentModificationException异常"><span class="post-toc-number">1.4.0.9.</span> <span class="post-toc-text">ConcurrentModificationException异常</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#线程安全的-List"><span class="post-toc-number">1.4.0.10.</span> <span class="post-toc-text">线程安全的 List</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#CopyOnWriteArrayList"><span class="post-toc-number">1.4.0.11.</span> <span class="post-toc-text">CopyOnWriteArrayList</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#线程安全的Set"><span class="post-toc-number">1.4.0.12.</span> <span class="post-toc-text">线程安全的Set</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#线程安全的Map"><span class="post-toc-number">1.4.0.13.</span> <span class="post-toc-text">线程安全的Map</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#ConcurrentHashMap"><span class="post-toc-number">1.4.0.14.</span> <span class="post-toc-text">ConcurrentHashMap</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#ConcurrentSkipListMap"><span class="post-toc-number">1.4.0.15.</span> <span class="post-toc-text">ConcurrentSkipListMap</span></a></li></ol></li></ol></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#Java-IO"><span class="post-toc-number">1.5.</span> <span class="post-toc-text">Java IO</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#操作系统的内核"><span class="post-toc-number">1.5.1.</span> <span class="post-toc-text">操作系统的内核</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#操作系统的用户态与内核态"><span class="post-toc-number">1.5.1.1.</span> <span class="post-toc-text">操作系统的用户态与内核态</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#为什么要有用户态与内核态"><span class="post-toc-number">1.5.1.2.</span> <span class="post-toc-text">为什么要有用户态与内核态?</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#用户态切换到内核态的几种方式"><span class="post-toc-number">1.5.1.3.</span> <span class="post-toc-text">用户态切换到内核态的几种方式</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#阻塞和非阻塞"><span class="post-toc-number">1.5.1.4.</span> <span class="post-toc-text">阻塞和非阻塞</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#同步与异步"><span class="post-toc-number">1.5.1.5.</span> <span class="post-toc-text">同步与异步</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#Linux-IO模型"><span class="post-toc-number">1.5.2.</span> <span class="post-toc-text">Linux IO模型</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#阻塞IO"><span class="post-toc-number">1.5.2.1.</span> <span class="post-toc-text">阻塞IO</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#非阻塞IO-网络IO模型"><span class="post-toc-number">1.5.2.2.</span> <span class="post-toc-text">非阻塞IO(网络IO模型)</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#多路复用IO-网络IO模型"><span class="post-toc-number">1.5.2.3.</span> <span class="post-toc-text">多路复用IO(网络IO模型)</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#信号驱动IO-网络IO模型"><span class="post-toc-number">1.5.2.4.</span> <span class="post-toc-text">信号驱动IO(网络IO模型)</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#异步IO"><span class="post-toc-number">1.5.2.5.</span> <span class="post-toc-text">异步IO</span></a></li></ol></li></ol></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#JVM"><span class="post-toc-number">1.6.</span> <span class="post-toc-text">JVM</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#JVM运行时内存分区"><span class="post-toc-number">1.6.1.</span> <span class="post-toc-text">JVM运行时内存分区</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#程序计数器"><span class="post-toc-number">1.6.1.1.</span> <span class="post-toc-text">程序计数器</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#程序计数器的特点"><span class="post-toc-number">1.6.1.2.</span> <span class="post-toc-text">程序计数器的特点</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Java虚拟机栈"><span class="post-toc-number">1.6.1.3.</span> <span class="post-toc-text">Java虚拟机栈</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#栈帧"><span class="post-toc-number">1.6.1.4.</span> <span class="post-toc-text">栈帧</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#局部变量表"><span class="post-toc-number">1.6.1.5.</span> <span class="post-toc-text">局部变量表</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#操作数栈"><span class="post-toc-number">1.6.1.6.</span> <span class="post-toc-text">操作数栈</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#动态连接"><span class="post-toc-number">1.6.1.7.</span> <span class="post-toc-text">动态连接</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#方法出口"><span class="post-toc-number">1.6.1.8.</span> <span class="post-toc-text">方法出口</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#本地方法栈"><span class="post-toc-number">1.6.1.9.</span> <span class="post-toc-text">本地方法栈</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#堆"><span class="post-toc-number">1.6.1.10.</span> <span class="post-toc-text">堆</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#方法区"><span class="post-toc-number">1.6.1.11.</span> <span class="post-toc-text">方法区</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#JavaVirtualMachineError"><span class="post-toc-number">1.6.2.</span> <span class="post-toc-text">JavaVirtualMachineError</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#StackOverflowError"><span class="post-toc-number">1.6.2.1.</span> <span class="post-toc-text">StackOverflowError</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#OutOfMemoryError"><span class="post-toc-number">1.6.2.2.</span> <span class="post-toc-text">OutOfMemoryError</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#简单了解类文件结构"><span class="post-toc-number">1.6.3.</span> <span class="post-toc-text">简单了解类文件结构</span></a></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#类的生命周期"><span class="post-toc-number">1.6.4.</span> <span class="post-toc-text">类的生命周期</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#类加载过程"><span class="post-toc-number">1.6.4.1.</span> <span class="post-toc-text">类加载过程</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#加载"><span class="post-toc-number">1.6.4.2.</span> <span class="post-toc-text">加载</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#连接"><span class="post-toc-number">1.6.4.3.</span> <span class="post-toc-text">连接</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#初始化"><span class="post-toc-number">1.6.4.4.</span> <span class="post-toc-text">初始化</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#使用"><span class="post-toc-number">1.6.4.5.</span> <span class="post-toc-text">使用</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#类的卸载"><span class="post-toc-number">1.6.4.6.</span> <span class="post-toc-text">类的卸载</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Java中类加载器有多少个"><span class="post-toc-number">1.6.4.7.</span> <span class="post-toc-text">Java中类加载器有多少个</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#类加载器的命名空间"><span class="post-toc-number">1.6.4.8.</span> <span class="post-toc-text">类加载器的命名空间</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#双亲委派机制"><span class="post-toc-number">1.6.4.9.</span> <span class="post-toc-text">双亲委派机制</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#为什么需要双亲委派机制"><span class="post-toc-number">1.6.4.10.</span> <span class="post-toc-text">为什么需要双亲委派机制?</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#双亲委派机制的实现原理"><span class="post-toc-number">1.6.4.11.</span> <span class="post-toc-text">双亲委派机制的实现原理?</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#JVM常量池"><span class="post-toc-number">1.6.5.</span> <span class="post-toc-text">JVM常量池</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Class常量池-静态常量池"><span class="post-toc-number">1.6.5.1.</span> <span class="post-toc-text">Class常量池(静态常量池)</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#运行时常量池"><span class="post-toc-number">1.6.5.2.</span> <span class="post-toc-text">运行时常量池</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#字符串常量池-全局常量池"><span class="post-toc-number">1.6.5.3.</span> <span class="post-toc-text">字符串常量池(全局常量池)</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#包装类型缓存池"><span class="post-toc-number">1.6.5.4.</span> <span class="post-toc-text">包装类型缓存池</span></a></li></ol></li></ol></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#GC"><span class="post-toc-number">1.7.</span> <span class="post-toc-text">GC</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#判断对象存活的方法"><span class="post-toc-number">1.7.1.</span> <span class="post-toc-text">判断对象存活的方法</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#引用计数法缺点"><span class="post-toc-number">1.7.1.1.</span> <span class="post-toc-text">引用计数法缺点</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#什么是GC-Root"><span class="post-toc-number">1.7.1.2.</span> <span class="post-toc-text">什么是GC Root ?</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#垃圾回收算法"><span class="post-toc-number">1.7.2.</span> <span class="post-toc-text">垃圾回收算法</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#复制算法-Copying"><span class="post-toc-number">1.7.2.1.</span> <span class="post-toc-text">复制算法(Copying)</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#标记-清除算法-Mark-Sweep"><span class="post-toc-number">1.7.2.2.</span> <span class="post-toc-text">标记-清除算法(Mark-Sweep)</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#标记-整理算法-Mark-Compact"><span class="post-toc-number">1.7.2.3.</span> <span class="post-toc-text">标记-整理算法(Mark-Compact)</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#分代收集算法"><span class="post-toc-number">1.7.2.4.</span> <span class="post-toc-text">分代收集算法</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#内存分配与垃圾回收策略"><span class="post-toc-number">1.7.2.5.</span> <span class="post-toc-text">内存分配与垃圾回收策略</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#一次GC的过程"><span class="post-toc-number">1.7.2.6.</span> <span class="post-toc-text">一次GC的过程</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#动态年龄阈值"><span class="post-toc-number">1.7.2.7.</span> <span class="post-toc-text">动态年龄阈值</span></a></li></ol></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#垃圾回收器"><span class="post-toc-number">1.7.3.</span> <span class="post-toc-text">垃圾回收器</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Serial串行收集器"><span class="post-toc-number">1.7.3.1.</span> <span class="post-toc-text">Serial串行收集器</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#Serial-Old-串行收集器-老年代版本"><span class="post-toc-number">1.7.3.2.</span> <span class="post-toc-text">Serial Old 串行收集器(老年代版本)</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#G1-收集器"><span class="post-toc-number">1.7.3.3.</span> <span class="post-toc-text">G1 收集器</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#G1回收器的特点"><span class="post-toc-number">1.7.3.4.</span> <span class="post-toc-text">G1回收器的特点</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#G1收集器回收过程"><span class="post-toc-number">1.7.3.5.</span> <span class="post-toc-text">G1收集器回收过程</span></a></li></ol></li></ol></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#Jdk新特性"><span class="post-toc-number">1.8.</span> <span class="post-toc-text">Jdk新特性</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#Jdk8新特性"><span class="post-toc-number">1.8.1.</span> <span class="post-toc-text">Jdk8新特性</span></a></li><li class="post-toc-item post-toc-level-3"><a class="post-toc-link" href="#Jdk9新特性"><span class="post-toc-number">1.8.2.</span> <span class="post-toc-text">Jdk9新特性</span></a></li></ol></li></ol>
            <!--<div id="toc" class="toc-article">-->
                <!--<strong class="toc-title">文章目录</strong>-->
                <!--<ol class="toc"><li class="toc-item toc-level-1"><a class="toc-link" href="#jdk-amp-jvm-amp-juc-部分图源-JavaGuide"><span class="toc-number">1.</span> <span class="toc-text">jdk&amp;jvm&amp;juc(部分图源:JavaGuide)</span></a><ol class="toc-child"><li class="toc-item toc-level-2"><a class="toc-link" href="#java基础知识"><span class="toc-number">1.1.</span> <span class="toc-text">java基础知识</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Java常见基础知识点"><span class="toc-number">1.1.1.</span> <span class="toc-text">Java常见基础知识点</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#面向对象和面向过程的区别"><span class="toc-number">1.1.1.1.</span> <span class="toc-text">面向对象和面向过程的区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#OracleJdk与OpenJdk的区别"><span class="toc-number">1.1.1.2.</span> <span class="toc-text">OracleJdk与OpenJdk的区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Java与C-的异同"><span class="toc-number">1.1.1.3.</span> <span class="toc-text">Java与C++的异同</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#JVM-JDK和JRE的区别"><span class="toc-number">1.1.1.4.</span> <span class="toc-text">JVM,JDK和JRE的区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Java语言的特点"><span class="toc-number">1.1.1.5.</span> <span class="toc-text">Java语言的特点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#面向对象的特征"><span class="toc-number">1.1.1.6.</span> <span class="toc-text">面向对象的特征</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#重载和重写的区别"><span class="toc-number">1.1.1.7.</span> <span class="toc-text">重载和重写的区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#接口与抽象类的区别"><span class="toc-number">1.1.1.8.</span> <span class="toc-text">接口与抽象类的区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Object类的方法有哪些"><span class="toc-number">1.1.1.9.</span> <span class="toc-text">Object类的方法有哪些?</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#静态属性方法和成员属性方法区别"><span class="toc-number">1.1.1.10.</span> <span class="toc-text">静态属性方法和成员属性方法区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#子类属性与父类属性初始化顺序"><span class="toc-number">1.1.1.11.</span> <span class="toc-text">子类属性与父类属性初始化顺序</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#自动拆箱和装箱"><span class="toc-number">1.1.1.12.</span> <span class="toc-text">自动拆箱和装箱</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#String为什么不可变"><span class="toc-number">1.1.1.13.</span> <span class="toc-text">String为什么不可变?</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#final关键字的作用"><span class="toc-number">1.1.1.14.</span> <span class="toc-text">final关键字的作用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#StringBuilder和StringBuffer区别"><span class="toc-number">1.1.1.15.</span> <span class="toc-text">StringBuilder和StringBuffer区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#equals知识点"><span class="toc-number">1.1.1.16.</span> <span class="toc-text">equals知识点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#深拷贝与浅拷贝"><span class="toc-number">1.1.1.17.</span> <span class="toc-text">深拷贝与浅拷贝</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#IO流分类"><span class="toc-number">1.1.1.18.</span> <span class="toc-text">IO流分类</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#使用字节流还是字符流"><span class="toc-number">1.1.1.19.</span> <span class="toc-text">使用字节流还是字符流?</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#BigDecimal"><span class="toc-number">1.1.1.20.</span> <span class="toc-text">BigDecimal</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Java异常体系结构"><span class="toc-number">1.1.1.21.</span> <span class="toc-text">Java异常体系结构</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Comparable和Comparator"><span class="toc-number">1.1.1.22.</span> <span class="toc-text">Comparable和Comparator</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#为什么要慎用-Arrays-asList"><span class="toc-number">1.1.1.23.</span> <span class="toc-text">为什么要慎用 Arrays.asList()?</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Java中引用的类型"><span class="toc-number">1.1.1.24.</span> <span class="toc-text">Java中引用的类型</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#对象在内存中的布局-64位"><span class="toc-number">1.2.</span> <span class="toc-text">对象在内存中的布局(64位)</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#对象头"><span class="toc-number">1.2.1.</span> <span class="toc-text">对象头</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#markword和metadata"><span class="toc-number">1.2.1.1.</span> <span class="toc-text">markword和metadata</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#实例数据"><span class="toc-number">1.2.1.2.</span> <span class="toc-text">实例数据</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#对齐填充"><span class="toc-number">1.2.1.3.</span> <span class="toc-text">对齐填充</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#jol工具查看对象布局"><span class="toc-number">1.2.2.</span> <span class="toc-text">jol工具查看对象布局</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#查看对象内存布局"><span class="toc-number">1.2.2.1.</span> <span class="toc-text">查看对象内存布局</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#hashcode"><span class="toc-number">1.2.2.2.</span> <span class="toc-text">hashcode</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#对象的hashcode返回的是对象的内存地址吗"><span class="toc-number">1.2.2.3.</span> <span class="toc-text">对象的hashcode返回的是对象的内存地址吗?</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#线程并发-JUC-AQS-CAS"><span class="toc-number">1.3.</span> <span class="toc-text">线程并发(JUC,AQS,CAS)</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#多线程"><span class="toc-number">1.3.1.</span> <span class="toc-text">多线程</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#进程和线程"><span class="toc-number">1.3.1.1.</span> <span class="toc-text">进程和线程</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#并发和并行"><span class="toc-number">1.3.1.2.</span> <span class="toc-text">并发和并行</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#多线程的利弊"><span class="toc-number">1.3.1.3.</span> <span class="toc-text">多线程的利弊</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#什么是上下文切换"><span class="toc-number">1.3.1.4.</span> <span class="toc-text">什么是上下文切换?</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#线程的优先级"><span class="toc-number">1.3.1.5.</span> <span class="toc-text">线程的优先级</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#线程的几种状态"><span class="toc-number">1.3.1.6.</span> <span class="toc-text">线程的几种状态</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#sleep方法和wait方法"><span class="toc-number">1.3.1.7.</span> <span class="toc-text">sleep方法和wait方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#stop-suspend-resume等方法为什么会被遗弃"><span class="toc-number">1.3.1.8.</span> <span class="toc-text">stop,suspend,resume等方法为什么会被遗弃</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#interrupt-interrupted-isInterrupted方法区别"><span class="toc-number">1.3.1.9.</span> <span class="toc-text">interrupt,interrupted,isInterrupted方法区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#join方法"><span class="toc-number">1.3.1.10.</span> <span class="toc-text">join方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#yield方法"><span class="toc-number">1.3.1.11.</span> <span class="toc-text">yield方法</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#并发"><span class="toc-number">1.3.2.</span> <span class="toc-text">并发</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#synchronized"><span class="toc-number">1.3.2.1.</span> <span class="toc-text">synchronized</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#synchronized底层原理"><span class="toc-number">1.3.2.2.</span> <span class="toc-text">synchronized底层原理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#synchronized-使用方法"><span class="toc-number">1.3.2.3.</span> <span class="toc-text">synchronized 使用方法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Synchronized和ReentrantLock的区别"><span class="toc-number">1.3.2.4.</span> <span class="toc-text">Synchronized和ReentrantLock的区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#乐观锁"><span class="toc-number">1.3.2.5.</span> <span class="toc-text">乐观锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#悲观锁"><span class="toc-number">1.3.2.6.</span> <span class="toc-text">悲观锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#独占锁"><span class="toc-number">1.3.2.7.</span> <span class="toc-text">独占锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#共享锁"><span class="toc-number">1.3.2.8.</span> <span class="toc-text">共享锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#公平锁"><span class="toc-number">1.3.2.9.</span> <span class="toc-text">公平锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#非公平锁"><span class="toc-number">1.3.2.10.</span> <span class="toc-text">非公平锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#可重入锁-递归锁"><span class="toc-number">1.3.2.11.</span> <span class="toc-text">可重入锁(递归锁)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#偏向锁"><span class="toc-number">1.3.2.12.</span> <span class="toc-text">偏向锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#轻量级锁"><span class="toc-number">1.3.2.13.</span> <span class="toc-text">轻量级锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#自旋锁"><span class="toc-number">1.3.2.14.</span> <span class="toc-text">自旋锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#自适应自旋锁"><span class="toc-number">1.3.2.15.</span> <span class="toc-text">自适应自旋锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#锁消除"><span class="toc-number">1.3.2.16.</span> <span class="toc-text">锁消除</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#死锁"><span class="toc-number">1.3.2.17.</span> <span class="toc-text">死锁</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#如何避免死锁"><span class="toc-number">1.3.2.18.</span> <span class="toc-text">如何避免死锁?</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#volatile"><span class="toc-number">1.3.3.</span> <span class="toc-text">volatile</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#volatile保证内存的可见性"><span class="toc-number">1.3.3.1.</span> <span class="toc-text">volatile保证内存的可见性</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#volatile禁止指令重排序"><span class="toc-number">1.3.3.2.</span> <span class="toc-text">volatile禁止指令重排序</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#volatile如何禁止指令重排序的"><span class="toc-number">1.3.3.3.</span> <span class="toc-text">volatile如何禁止指令重排序的?</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#volatile不保证原子性"><span class="toc-number">1.3.3.4.</span> <span class="toc-text">volatile不保证原子性</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#CAS"><span class="toc-number">1.3.4.</span> <span class="toc-text">CAS</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#CAS在JAVA中的底层实现-Atomic原子类实现"><span class="toc-number">1.3.4.1.</span> <span class="toc-text">CAS在JAVA中的底层实现(Atomic原子类实现)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#CAS的缺点"><span class="toc-number">1.3.4.2.</span> <span class="toc-text">CAS的缺点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#解决ABA问题"><span class="toc-number">1.3.4.3.</span> <span class="toc-text">解决ABA问题</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ThreadLocal"><span class="toc-number">1.3.4.4.</span> <span class="toc-text">ThreadLocal</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ThreadLocal引发的内存泄露"><span class="toc-number">1.3.4.5.</span> <span class="toc-text">ThreadLocal引发的内存泄露</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#线程池的好处"><span class="toc-number">1.3.4.6.</span> <span class="toc-text">线程池的好处</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#线程池构造参数"><span class="toc-number">1.3.4.7.</span> <span class="toc-text">线程池构造参数</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#阿里巴巴开发者手册不建议开发者使用Executors创建线程池"><span class="toc-number">1.3.4.8.</span> <span class="toc-text">阿里巴巴开发者手册不建议开发者使用Executors创建线程池</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#AQS-AbstractQueuedSynchronizer"><span class="toc-number">1.3.5.</span> <span class="toc-text">AQS(AbstractQueuedSynchronizer)</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#AQS概述"><span class="toc-number">1.3.5.1.</span> <span class="toc-text">AQS概述</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#AQS的两种共享资源的访问方式"><span class="toc-number">1.3.5.2.</span> <span class="toc-text">AQS的两种共享资源的访问方式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#lock-tryLock和lockInterruptibly区别"><span class="toc-number">1.3.5.3.</span> <span class="toc-text">lock,tryLock和lockInterruptibly区别</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#CountDownLatch"><span class="toc-number">1.3.5.4.</span> <span class="toc-text">CountDownLatch</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Semaphore"><span class="toc-number">1.3.5.5.</span> <span class="toc-text">Semaphore</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#CycliBarrier"><span class="toc-number">1.3.5.6.</span> <span class="toc-text">CycliBarrier</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ReentrantReadWriteLock如何区分读写锁的"><span class="toc-number">1.3.5.7.</span> <span class="toc-text">ReentrantReadWriteLock如何区分读写锁的?</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Java集合"><span class="toc-number">1.4.</span> <span class="toc-text">Java集合</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#HashMap的特点"><span class="toc-number">1.4.0.1.</span> <span class="toc-text">HashMap的特点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#HashMap的长度-容量-为什么要设计成2的幂？"><span class="toc-number">1.4.0.2.</span> <span class="toc-text">HashMap的长度(容量)为什么要设计成2的幂？</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#HashTable的特点"><span class="toc-number">1.4.0.3.</span> <span class="toc-text">HashTable的特点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#TreeMap"><span class="toc-number">1.4.0.4.</span> <span class="toc-text">TreeMap</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ArrayList的特点"><span class="toc-number">1.4.0.5.</span> <span class="toc-text">ArrayList的特点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Vector的特点"><span class="toc-number">1.4.0.6.</span> <span class="toc-text">Vector的特点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#LinkedList的特点"><span class="toc-number">1.4.0.7.</span> <span class="toc-text">LinkedList的特点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Set"><span class="toc-number">1.4.0.8.</span> <span class="toc-text">Set</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ConcurrentModificationException异常"><span class="toc-number">1.4.0.9.</span> <span class="toc-text">ConcurrentModificationException异常</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#线程安全的-List"><span class="toc-number">1.4.0.10.</span> <span class="toc-text">线程安全的 List</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#CopyOnWriteArrayList"><span class="toc-number">1.4.0.11.</span> <span class="toc-text">CopyOnWriteArrayList</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#线程安全的Set"><span class="toc-number">1.4.0.12.</span> <span class="toc-text">线程安全的Set</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#线程安全的Map"><span class="toc-number">1.4.0.13.</span> <span class="toc-text">线程安全的Map</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ConcurrentHashMap"><span class="toc-number">1.4.0.14.</span> <span class="toc-text">ConcurrentHashMap</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ConcurrentSkipListMap"><span class="toc-number">1.4.0.15.</span> <span class="toc-text">ConcurrentSkipListMap</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Java-IO"><span class="toc-number">1.5.</span> <span class="toc-text">Java IO</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#操作系统的内核"><span class="toc-number">1.5.1.</span> <span class="toc-text">操作系统的内核</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#操作系统的用户态与内核态"><span class="toc-number">1.5.1.1.</span> <span class="toc-text">操作系统的用户态与内核态</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#为什么要有用户态与内核态"><span class="toc-number">1.5.1.2.</span> <span class="toc-text">为什么要有用户态与内核态?</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#用户态切换到内核态的几种方式"><span class="toc-number">1.5.1.3.</span> <span class="toc-text">用户态切换到内核态的几种方式</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#阻塞和非阻塞"><span class="toc-number">1.5.1.4.</span> <span class="toc-text">阻塞和非阻塞</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#同步与异步"><span class="toc-number">1.5.1.5.</span> <span class="toc-text">同步与异步</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Linux-IO模型"><span class="toc-number">1.5.2.</span> <span class="toc-text">Linux IO模型</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#阻塞IO"><span class="toc-number">1.5.2.1.</span> <span class="toc-text">阻塞IO</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#非阻塞IO-网络IO模型"><span class="toc-number">1.5.2.2.</span> <span class="toc-text">非阻塞IO(网络IO模型)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#多路复用IO-网络IO模型"><span class="toc-number">1.5.2.3.</span> <span class="toc-text">多路复用IO(网络IO模型)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#信号驱动IO-网络IO模型"><span class="toc-number">1.5.2.4.</span> <span class="toc-text">信号驱动IO(网络IO模型)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#异步IO"><span class="toc-number">1.5.2.5.</span> <span class="toc-text">异步IO</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#JVM"><span class="toc-number">1.6.</span> <span class="toc-text">JVM</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#JVM运行时内存分区"><span class="toc-number">1.6.1.</span> <span class="toc-text">JVM运行时内存分区</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#程序计数器"><span class="toc-number">1.6.1.1.</span> <span class="toc-text">程序计数器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#程序计数器的特点"><span class="toc-number">1.6.1.2.</span> <span class="toc-text">程序计数器的特点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Java虚拟机栈"><span class="toc-number">1.6.1.3.</span> <span class="toc-text">Java虚拟机栈</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#栈帧"><span class="toc-number">1.6.1.4.</span> <span class="toc-text">栈帧</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#局部变量表"><span class="toc-number">1.6.1.5.</span> <span class="toc-text">局部变量表</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#操作数栈"><span class="toc-number">1.6.1.6.</span> <span class="toc-text">操作数栈</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#动态连接"><span class="toc-number">1.6.1.7.</span> <span class="toc-text">动态连接</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#方法出口"><span class="toc-number">1.6.1.8.</span> <span class="toc-text">方法出口</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#本地方法栈"><span class="toc-number">1.6.1.9.</span> <span class="toc-text">本地方法栈</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#堆"><span class="toc-number">1.6.1.10.</span> <span class="toc-text">堆</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#方法区"><span class="toc-number">1.6.1.11.</span> <span class="toc-text">方法区</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#JavaVirtualMachineError"><span class="toc-number">1.6.2.</span> <span class="toc-text">JavaVirtualMachineError</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#StackOverflowError"><span class="toc-number">1.6.2.1.</span> <span class="toc-text">StackOverflowError</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#OutOfMemoryError"><span class="toc-number">1.6.2.2.</span> <span class="toc-text">OutOfMemoryError</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#简单了解类文件结构"><span class="toc-number">1.6.3.</span> <span class="toc-text">简单了解类文件结构</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#类的生命周期"><span class="toc-number">1.6.4.</span> <span class="toc-text">类的生命周期</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#类加载过程"><span class="toc-number">1.6.4.1.</span> <span class="toc-text">类加载过程</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#加载"><span class="toc-number">1.6.4.2.</span> <span class="toc-text">加载</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#连接"><span class="toc-number">1.6.4.3.</span> <span class="toc-text">连接</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#初始化"><span class="toc-number">1.6.4.4.</span> <span class="toc-text">初始化</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#使用"><span class="toc-number">1.6.4.5.</span> <span class="toc-text">使用</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#类的卸载"><span class="toc-number">1.6.4.6.</span> <span class="toc-text">类的卸载</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Java中类加载器有多少个"><span class="toc-number">1.6.4.7.</span> <span class="toc-text">Java中类加载器有多少个</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#类加载器的命名空间"><span class="toc-number">1.6.4.8.</span> <span class="toc-text">类加载器的命名空间</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#双亲委派机制"><span class="toc-number">1.6.4.9.</span> <span class="toc-text">双亲委派机制</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#为什么需要双亲委派机制"><span class="toc-number">1.6.4.10.</span> <span class="toc-text">为什么需要双亲委派机制?</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#双亲委派机制的实现原理"><span class="toc-number">1.6.4.11.</span> <span class="toc-text">双亲委派机制的实现原理?</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#JVM常量池"><span class="toc-number">1.6.5.</span> <span class="toc-text">JVM常量池</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Class常量池-静态常量池"><span class="toc-number">1.6.5.1.</span> <span class="toc-text">Class常量池(静态常量池)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#运行时常量池"><span class="toc-number">1.6.5.2.</span> <span class="toc-text">运行时常量池</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#字符串常量池-全局常量池"><span class="toc-number">1.6.5.3.</span> <span class="toc-text">字符串常量池(全局常量池)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#包装类型缓存池"><span class="toc-number">1.6.5.4.</span> <span class="toc-text">包装类型缓存池</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#GC"><span class="toc-number">1.7.</span> <span class="toc-text">GC</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#判断对象存活的方法"><span class="toc-number">1.7.1.</span> <span class="toc-text">判断对象存活的方法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#引用计数法缺点"><span class="toc-number">1.7.1.1.</span> <span class="toc-text">引用计数法缺点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#什么是GC-Root"><span class="toc-number">1.7.1.2.</span> <span class="toc-text">什么是GC Root ?</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#垃圾回收算法"><span class="toc-number">1.7.2.</span> <span class="toc-text">垃圾回收算法</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#复制算法-Copying"><span class="toc-number">1.7.2.1.</span> <span class="toc-text">复制算法(Copying)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#标记-清除算法-Mark-Sweep"><span class="toc-number">1.7.2.2.</span> <span class="toc-text">标记-清除算法(Mark-Sweep)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#标记-整理算法-Mark-Compact"><span class="toc-number">1.7.2.3.</span> <span class="toc-text">标记-整理算法(Mark-Compact)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#分代收集算法"><span class="toc-number">1.7.2.4.</span> <span class="toc-text">分代收集算法</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#内存分配与垃圾回收策略"><span class="toc-number">1.7.2.5.</span> <span class="toc-text">内存分配与垃圾回收策略</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#一次GC的过程"><span class="toc-number">1.7.2.6.</span> <span class="toc-text">一次GC的过程</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#动态年龄阈值"><span class="toc-number">1.7.2.7.</span> <span class="toc-text">动态年龄阈值</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#垃圾回收器"><span class="toc-number">1.7.3.</span> <span class="toc-text">垃圾回收器</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Serial串行收集器"><span class="toc-number">1.7.3.1.</span> <span class="toc-text">Serial串行收集器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Serial-Old-串行收集器-老年代版本"><span class="toc-number">1.7.3.2.</span> <span class="toc-text">Serial Old 串行收集器(老年代版本)</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#G1-收集器"><span class="toc-number">1.7.3.3.</span> <span class="toc-text">G1 收集器</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#G1回收器的特点"><span class="toc-number">1.7.3.4.</span> <span class="toc-text">G1回收器的特点</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#G1收集器回收过程"><span class="toc-number">1.7.3.5.</span> <span class="toc-text">G1收集器回收过程</span></a></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#Jdk新特性"><span class="toc-number">1.8.</span> <span class="toc-text">Jdk新特性</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#Jdk8新特性"><span class="toc-number">1.8.1.</span> <span class="toc-text">Jdk8新特性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#Jdk9新特性"><span class="toc-number">1.8.2.</span> <span class="toc-text">Jdk9新特性</span></a></li></ol></li></ol></li></ol>-->
            <!--</div>-->
        </nav>
    </aside>




<article id="post-jdk_jvm_juc-learning" class="post-article article-type-post fade" itemprop="blogPost">

    <div class="post-card">
        <h1 class="post-card-title">JUC和JVM</h1>
        <div class="post-meta">
            <time class="post-time" title="2020-04-07 16:44:22" datetime="2020-04-07T08:44:22.000Z" itemprop="datePublished">2020-04-07</time>

            
	<ul class="article-category-list"><li class="article-category-list-item"><a class="article-category-list-link" href="/categories/JUC/">JUC</a><ul class="article-category-list-child"><li class="article-category-list-item"><a class="article-category-list-link" href="/categories/JUC/JVM/">JVM</a></li></ul></li></ul>



            
<span id="busuanzi_container_page_pv" title="文章总阅读量" style="display:none">
    <i class="icon icon-eye icon-pr"></i><span id="busuanzi_value_page_pv"></span>
</span>


        </div>
        <div class="post-content" id="post-content" itemprop="postContent">
            <!-- TOC -->
<ul>
<li><a href="#jdkjvmjuc部分图源javaguide">jdk&amp;jvm&amp;juc(部分图源:<a href="https://github.com/Snailclimb/JavaGuide" target="_blank" rel="noopener">JavaGuide</a>)</a><ul>
<li><a href="#java基础知识">java基础知识</a><ul>
<li><a href="#java常见基础知识点">Java常见基础知识点</a><ul>
<li><a href="#面向对象和面向过程的区别">面向对象和面向过程的区别</a></li>
<li><a href="#oraclejdk与openjdk的区别">OracleJdk与OpenJdk的区别</a></li>
<li><a href="#java与c的异同">Java与C  的异同</a></li>
<li><a href="#jvmjdk和jre的区别">JVM,JDK和JRE的区别</a></li>
<li><a href="#java语言的特点">Java语言的特点</a></li>
<li><a href="#面向对象的特征">面向对象的特征</a></li>
<li><a href="#重载和重写的区别">重载和重写的区别</a></li>
<li><a href="#接口与抽象类的区别">接口与抽象类的区别</a></li>
<li><a href="#object类的方法有哪些">Object类的方法有哪些?</a></li>
<li><a href="#静态属性方法和成员属性方法区别">静态属性方法和成员属性方法区别</a></li>
<li><a href="#子类属性与父类属性初始化顺序">子类属性与父类属性初始化顺序</a></li>
<li><a href="#自动拆箱和装箱">自动拆箱和装箱</a></li>
<li><a href="#string为什么不可变">String为什么不可变?</a></li>
<li><a href="#final关键字的作用">final关键字的作用</a></li>
<li><a href="#stringbuilder和stringbuffer区别">StringBuilder和StringBuffer区别</a></li>
<li><a href="#equals知识点">equals知识点</a></li>
<li><a href="#深拷贝与浅拷贝">深拷贝与浅拷贝</a></li>
<li><a href="#io流分类">IO流分类</a></li>
<li><a href="#使用字节流还是字符流">使用字节流还是字符流?</a></li>
<li><a href="#bigdecimal">BigDecimal</a></li>
<li><a href="#java异常体系结构">Java异常体系结构</a></li>
<li><a href="#comparable和comparator">Comparable和Comparator</a></li>
<li><a href="#为什么要慎用-arraysaslist">为什么要慎用 Arrays.asList()?</a></li>
<li><a href="#java中引用的类型">Java中引用的类型</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#对象在内存中的布局64位">对象在内存中的布局(64位)</a><ul>
<li><a href="#对象头">对象头</a><ul>
<li><a href="#markword和metadata">markword和metadata</a></li>
<li><a href="#实例数据">实例数据</a></li>
<li><a href="#对齐填充">对齐填充</a></li>
</ul>
</li>
<li><a href="#jol工具查看对象布局">jol工具查看对象布局</a><ul>
<li><a href="#查看对象内存布局">查看对象内存布局</a></li>
<li><a href="#hashcode">hashcode</a></li>
<li><a href="#对象的hashcode返回的是对象的内存地址吗">对象的hashcode返回的是对象的内存地址吗?</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#线程并发jucaqscas">线程并发(JUC,AQS,CAS)</a><ul>
<li><a href="#多线程">多线程</a><ul>
<li><a href="#进程和线程">进程和线程</a></li>
<li><a href="#并发和并行">并发和并行</a></li>
<li><a href="#多线程的利弊">多线程的利弊</a></li>
<li><a href="#什么是上下文切换">什么是上下文切换?</a></li>
<li><a href="#线程的优先级">线程的优先级</a></li>
<li><a href="#线程的几种状态">线程的几种状态</a></li>
<li><a href="#sleep方法和wait方法">sleep方法和wait方法</a></li>
<li><a href="#stopsuspendresume等方法为什么会被遗弃">stop,suspend,resume等方法为什么会被遗弃</a></li>
<li><a href="#interruptinterruptedisinterrupted方法区别">interrupt,interrupted,isInterrupted方法区别</a></li>
<li><a href="#join方法">join方法</a></li>
<li><a href="#yield方法">yield方法</a></li>
</ul>
</li>
<li><a href="#并发">并发</a><ul>
<li><a href="#synchronized">synchronized</a></li>
<li><a href="#synchronized底层原理">synchronized底层原理</a></li>
<li><a href="#synchronized-使用方法">synchronized 使用方法</a></li>
<li><a href="#synchronized和reentrantlock的区别">Synchronized和ReentrantLock的区别</a></li>
<li><a href="#乐观锁">乐观锁</a></li>
<li><a href="#悲观锁">悲观锁</a></li>
<li><a href="#独占锁">独占锁</a></li>
<li><a href="#共享锁">共享锁</a></li>
<li><a href="#公平锁">公平锁</a></li>
<li><a href="#非公平锁">非公平锁</a></li>
<li><a href="#可重入锁递归锁">可重入锁(递归锁)</a></li>
<li><a href="#偏向锁">偏向锁</a></li>
<li><a href="#轻量级锁">轻量级锁</a></li>
<li><a href="#自旋锁">自旋锁</a></li>
<li><a href="#自适应自旋锁">自适应自旋锁</a></li>
<li><a href="#锁消除">锁消除</a></li>
<li><a href="#锁粗化">锁粗化</a></li>
<li><a href="#死锁">死锁</a></li>
<li><a href="#如何避免死锁">如何避免死锁?</a></li>
</ul>
</li>
<li><a href="#volatile">volatile</a><ul>
<li><a href="#volatile保证内存的可见性">volatile保证内存的可见性</a></li>
<li><a href="#volatile禁止指令重排序">volatile禁止指令重排序</a></li>
<li><a href="#volatile如何禁止指令重排序的">volatile如何禁止指令重排序的?</a></li>
<li><a href="#volatile不保证原子性">volatile不保证原子性</a></li>
</ul>
</li>
<li><a href="#cas">CAS</a><ul>
<li><a href="#cas在java中的底层实现atomic原子类实现">CAS在JAVA中的底层实现(Atomic原子类实现)</a></li>
<li><a href="#cas的缺点">CAS的缺点</a></li>
<li><a href="#解决aba问题">解决ABA问题</a></li>
<li><a href="#threadlocal">ThreadLocal</a></li>
<li><a href="#threadlocal引发的内存泄露">ThreadLocal引发的内存泄露:</a></li>
<li><a href="#线程池的好处">线程池的好处</a></li>
<li><a href="#线程池构造参数">线程池构造参数</a></li>
<li><a href="#阿里巴巴开发者手册不建议开发者使用executors创建线程池">阿里巴巴开发者手册不建议开发者使用Executors创建线程池</a></li>
</ul>
</li>
<li><a href="#aqsabstractqueuedsynchronizer">AQS(AbstractQueuedSynchronizer)</a><ul>
<li><a href="#aqs概述">AQS概述</a></li>
<li><a href="#aqs的两种共享资源的访问方式">AQS的两种共享资源的访问方式</a></li>
<li><a href="#locktrylock和lockinterruptibly区别">lock,tryLock和lockInterruptibly区别</a></li>
<li><a href="#countdownlatch">CountDownLatch</a></li>
<li><a href="#semaphore">Semaphore</a></li>
<li><a href="#cyclibarrier">CycliBarrier</a></li>
<li><a href="#reentrantreadwritelock如何区分读写锁的">ReentrantReadWriteLock如何区分读写锁的?</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#java集合">Java集合</a><ul>
<li><a href="#hashmap的特点">HashMap的特点</a></li>
<li><a href="#hashmap的长度容量为什么要设计成2的幂">HashMap的长度(容量)为什么要设计成2的幂？</a></li>
<li><a href="#hashtable的特点">HashTable的特点</a></li>
<li><a href="#treemap">TreeMap</a></li>
<li><a href="#arraylist的特点">ArrayList的特点</a></li>
<li><a href="#vector的特点">Vector的特点</a></li>
<li><a href="#linkedlist的特点">LinkedList的特点</a></li>
<li><a href="#set">Set</a></li>
<li><a href="#concurrentmodificationexception异常">ConcurrentModificationException异常</a></li>
<li><a href="#线程安全的-list">线程安全的 List</a></li>
<li><a href="#copyonwritearraylist">CopyOnWriteArrayList</a></li>
<li><a href="#线程安全的set">线程安全的Set</a></li>
<li><a href="#线程安全的map">线程安全的Map</a></li>
<li><a href="#concurrenthashmap">ConcurrentHashMap</a></li>
<li><a href="#concurrentskiplistmap">ConcurrentSkipListMap</a></li>
</ul>
</li>
<li><a href="#java-io">Java IO</a><ul>
<li><a href="#操作系统的内核">操作系统的内核</a><ul>
<li><a href="#操作系统的用户态与内核态">操作系统的用户态与内核态</a></li>
<li><a href="#为什么要有用户态与内核态">为什么要有用户态与内核态?</a></li>
<li><a href="#用户态切换到内核态的几种方式">用户态切换到内核态的几种方式</a></li>
<li><a href="#阻塞和非阻塞">阻塞和非阻塞</a></li>
<li><a href="#同步与异步">同步与异步</a></li>
</ul>
</li>
<li><a href="#linux-io模型">Linux IO模型</a><ul>
<li><a href="#阻塞io">阻塞IO</a></li>
<li><a href="#非阻塞io网络io模型">非阻塞IO(网络IO模型)</a></li>
<li><a href="#多路复用io网络io模型">多路复用IO(网络IO模型)</a></li>
<li><a href="#信号驱动io网络io模型">信号驱动IO(网络IO模型)</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#jvm">JVM</a><ul>
<li><a href="#jvm运行时内存分区">JVM运行时内存分区</a><ul>
<li><a href="#程序计数器">程序计数器</a></li>
<li><a href="#程序计数器的特点">程序计数器的特点</a></li>
<li><a href="#java虚拟机栈">Java虚拟机栈</a></li>
<li><a href="#栈帧">栈帧</a></li>
<li><a href="#局部变量表">局部变量表</a></li>
<li><a href="#操作数栈">操作数栈</a></li>
<li><a href="#动态连接">动态连接</a></li>
<li><a href="#方法出口">方法出口</a></li>
<li><a href="#本地方法栈">本地方法栈</a></li>
<li><a href="#堆">堆</a></li>
<li><a href="#方法区">方法区</a></li>
</ul>
</li>
<li><a href="#javavirtualmachineerror">JavaVirtualMachineError</a><ul>
<li><a href="#stackoverflowerror">StackOverflowError</a></li>
<li><a href="#outofmemoryerror">OutOfMemoryError</a></li>
</ul>
</li>
<li><a href="#简单了解类文件结构">简单了解类文件结构</a></li>
<li><a href="#类的生命周期">类的生命周期</a><ul>
<li><a href="#类加载过程">类加载过程</a></li>
<li><a href="#加载">加载</a></li>
<li><a href="#连接">连接</a></li>
<li><a href="#初始化">初始化</a></li>
<li><a href="#使用">使用</a></li>
<li><a href="#类的卸载">类的卸载</a></li>
<li><a href="#java中类加载器有多少个">Java中类加载器有多少个</a></li>
<li><a href="#类加载器的命名空间">类加载器的命名空间</a></li>
<li><a href="#双亲委派机制">双亲委派机制</a></li>
<li><a href="#为什么需要双亲委派机制">为什么需要双亲委派机制?</a></li>
<li><a href="#双亲委派机制的实现原理">双亲委派机制的实现原理?</a></li>
</ul>
</li>
<li><a href="#jvm常量池">JVM常量池</a><ul>
<li><a href="#class常量池静态常量池">Class常量池(静态常量池)</a></li>
<li><a href="#运行时常量池">运行时常量池</a></li>
<li><a href="#字符串常量池全局常量池">字符串常量池(全局常量池)</a></li>
<li><a href="#包装类型缓存池">包装类型缓存池</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#gc">GC</a><ul>
<li><a href="#判断对象存活的方法">判断对象存活的方法</a><ul>
<li><a href="#引用计数法缺点">引用计数法缺点</a></li>
<li><a href="#什么是gc-root-">什么是GC Root ?</a></li>
</ul>
</li>
<li><a href="#垃圾回收算法">垃圾回收算法</a><ul>
<li><a href="#复制算法copying">复制算法(Copying)</a></li>
<li><a href="#标记-清除算法mark-sweep">标记-清除算法(Mark-Sweep)</a></li>
<li><a href="#标记-整理算法mark-compact">标记-整理算法(Mark-Compact)</a></li>
<li><a href="#分代收集算法">分代收集算法</a></li>
<li><a href="#内存分配与垃圾回收策略">内存分配与垃圾回收策略</a></li>
<li><a href="#一次gc的过程">一次GC的过程</a></li>
<li><a href="#动态年龄阈值">动态年龄阈值</a></li>
</ul>
</li>
<li><a href="#垃圾回收器">垃圾回收器</a><ul>
<li><a href="#serial串行收集器">Serial串行收集器</a></li>
<li><a href="#serial-old-串行收集器老年代版本">Serial Old 串行收集器(老年代版本)</a></li>
<li><a href="#parallel-scavenge-并行多线程收集器">Parallel Scavenge 并行多线程收集器</a></li>
<li><a href="#parallel-old-并行收集器老年代版本">Parallel Old 并行收集器(老年代版本)</a></li>
<li><a href="#parnew-多线程收集器">ParNew 多线程收集器</a></li>
<li><a href="#cms-并发标记清除收集器">CMS 并发标记清除收集器</a></li>
<li><a href="#cms收集器回收过程">CMS收集器回收过程</a></li>
<li><a href="#g1-收集器">G1 收集器</a></li>
<li><a href="#g1回收器的特点">G1回收器的特点</a></li>
<li><a href="#g1收集器回收过程">G1收集器回收过程</a></li>
</ul>
</li>
</ul>
</li>
<li><a href="#jvm调优相关">JVM调优相关</a><ul>
<li><a href="#jvm常见参数">JVM常见参数</a><ul>
<li><a href="#堆栈相关">堆栈相关</a></li>
<li><a href="#gc相关">GC相关</a></li>
<li><a href="#其他">其他</a></li>
</ul>
</li>
<li><a href="#java常用调优命令和工具">Java常用调优命令和工具</a></li>
</ul>
</li>
<li><a href="#jdk新特性">Jdk新特性</a><ul>
<li><a href="#jdk8新特性">Jdk8新特性</a></li>
<li><a href="#jdk9新特性">Jdk9新特性</a></li>
</ul>
</li>
</ul>
</li>
</ul>
<!-- /TOC -->
<h1 id="jdk-amp-jvm-amp-juc-部分图源-JavaGuide"><a href="#jdk-amp-jvm-amp-juc-部分图源-JavaGuide" class="headerlink" title="jdk&amp;jvm&amp;juc(部分图源:JavaGuide)"></a>jdk&amp;jvm&amp;juc(部分图源:<a href="https://github.com/Snailclimb/JavaGuide" target="_blank" rel="noopener">JavaGuide</a>)</h1><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">如有错误之处，敬请各位同学指教。</span><br></pre></td></tr></table></figure>
<p><strong>PS:以下部分内容希望各位同学下载openjdk的源码,亲自实践。</strong></p>
<p>openjdk8u:</p>
<ul>
<li>hotspot:<a href="http://hg.openjdk.java.net/jdk8u/hs-dev/hotspot/archive/tip.tar.gz" target="_blank" rel="noopener">hotspot</a></li>
<li>openjdk:<a href="https://hg.openjdk.java.net/jdk8u/hs-dev/jdk/archive/tip.tar.gz" target="_blank" rel="noopener">jdk</a></li>
</ul>
<h2 id="java基础知识"><a href="#java基础知识" class="headerlink" title="java基础知识"></a>java基础知识</h2><p><strong>PS:以下部分内容希望各位同学下载openjdk的源码,亲自实践。</strong></p>
<p>openjdk8u:</p>
<ul>
<li>hotspot:<a href="http://hg.openjdk.java.net/jdk8u/hs-dev/hotspot/archive/tip.tar.gz" target="_blank" rel="noopener">hotspot</a></li>
<li>openjdk:<a href="https://hg.openjdk.java.net/jdk8u/hs-dev/jdk/archive/tip.tar.gz" target="_blank" rel="noopener">jdk</a></li>
</ul>
<h3 id="Java常见基础知识点"><a href="#Java常见基础知识点" class="headerlink" title="Java常见基础知识点"></a>Java常见基础知识点</h3><h4 id="面向对象和面向过程的区别"><a href="#面向对象和面向过程的区别" class="headerlink" title="面向对象和面向过程的区别"></a>面向对象和面向过程的区别</h4><p>首先面向过程和面向对象的语言没有具体的性能高下之分,要依据每种语言的设计来做参考.<br>个人认为面向过程与面向对象的最大区别在于: <strong>面向过程的语言是结构化的,面向对象的语言是模块化的。</strong><br><strong>模块化的代码比结构化的代码更易于维护,复用与扩展。</strong></p>
<h4 id="OracleJdk与OpenJdk的区别"><a href="#OracleJdk与OpenJdk的区别" class="headerlink" title="OracleJdk与OpenJdk的区别"></a>OracleJdk与OpenJdk的区别</h4><p>OpenJdk是基于Sum捐赠的HotSpot的源代码开发的,是开源的。<br>OracleJdk是Oracle对Jdk的商业化版本,由Oracle发布并维护.<br>因此OracleJdk比OpenJdk更可靠。</p>
<h4 id="Java与C-的异同"><a href="#Java与C-的异同" class="headerlink" title="Java与C++的异同"></a>Java与C++的异同</h4><ul>
<li><p>Java和C++都是基于面向对象思想的语言。</p>
</li>
<li><p>Java不提供指针来访问内存。C++允许指针访问内存。</p>
</li>
<li><p>垃圾回收机制。Java无需开发者手动释放内存,因为Java有垃圾回收机制;C++则需要开发者手动释放内存。因此Java在内存管理上相对C++更安全。</p>
</li>
<li><p>Java不支持多继承，而C++支持。</p>
</li>
</ul>
<h4 id="JVM-JDK和JRE的区别"><a href="#JVM-JDK和JRE的区别" class="headerlink" title="JVM,JDK和JRE的区别"></a>JVM,JDK和JRE的区别</h4><ul>
<li><p>JVM: JVM(java virtual machine)是java虚拟机</p>
</li>
<li><p>JRE: JRE(java runtime environment)是java运行时环境</p>
</li>
<li><p>JDK: JDK(java development kit)是java开发工具包,不仅包含了jre和jvm,还提供了javac编译器和javadoc等其他开发所需的工具</p>
</li>
</ul>
<h4 id="Java语言的特点"><a href="#Java语言的特点" class="headerlink" title="Java语言的特点"></a>Java语言的特点</h4><ul>
<li><p>面向对象</p>
</li>
<li><p>平台无关性,也就是跨平台(依靠JVM)</p>
</li>
<li><p>支持多线程</p>
</li>
<li><p>支持便捷的网络编程</p>
</li>
<li><p>编译与解释(JIT)</p>
</li>
<li><p>安全(个人认为所有语言写出来的代码的安全性是开发者决定的,<br>而不是语言本身决定的,语言能决定的只是提供方便或不便的安全的API)</p>
</li>
</ul>
<h4 id="面向对象的特征"><a href="#面向对象的特征" class="headerlink" title="面向对象的特征"></a>面向对象的特征</h4><p>面向对象三大特征:封装,继承,多态。</p>
<ul>
<li><p>封装: 封装是隐藏对象属性和的实现细节,只对外提供可访问或修改的接口。<br><strong>封装的目的是为了简化编程和增加程序的安全性,使得使用者无需了解对象的具体实现细节。</strong></p>
</li>
<li><p>继承: 继承是 在已存在的类上定义新的类的技术。<br>在Java中,已存在的类被称为基类(父类),新的类叫做派生类(子类).子类拥有父类的所有属性,方法。<br>但是子类对于父类中私有的方法或属性只是拥有,并不能访问和使用。<br><strong>继承的目的主要是为了代码的复用.</strong></p>
</li>
<li><p>多态: 多态指的是相同类型的对象,调用其相同的方法,参数也相同,但是它的表现形式也就是结果不同。<br><strong>多态的目的是为了程序的可扩展性和维护性。</strong><br>在Java中可以使用继承与接口2大特性实现多态。</p>
</li>
</ul>
<h4 id="重载和重写的区别"><a href="#重载和重写的区别" class="headerlink" title="重载和重写的区别"></a>重载和重写的区别</h4><p>个人认为重载和重写完全没有可比性,不知道为啥老有人喜欢拿它们做比较。</p>
<ul>
<li><p>重载: 重载是描述一个类中有多个方法名相同的方法，但是它们的参数,类型,返回值,参数的顺序可能不同，表现形式也就不同。</p>
</li>
<li><p>重写: 重写是描述子类对父类的某个方法的逻辑进行了重新编写,但重写的只是方法的内容,<br>方法名,参数,类型,顺序,返回值都是不变的。</p>
</li>
</ul>
<h4 id="接口与抽象类的区别"><a href="#接口与抽象类的区别" class="headerlink" title="接口与抽象类的区别"></a>接口与抽象类的区别</h4><ul>
<li><p>接口需要被实现,而抽象类是需要被继承的。</p>
</li>
<li><p>接口里的方法都是公共抽象的，而抽象类既允许抽象也允许非抽象的方法(在jdk8中,接口被允许定义default方法,jdk9中还允许定义private私有方法)。</p>
</li>
<li><p>一个类允许实现多个接口,但只允许继承一个抽象父类。</p>
</li>
<li><p>接口是对类的规范,规范的是行为能力。而抽象类是对类的抽象,抽象的是逻辑。</p>
</li>
</ul>
<h4 id="Object类的方法有哪些"><a href="#Object类的方法有哪些" class="headerlink" title="Object类的方法有哪些?"></a>Object类的方法有哪些?</h4><ol>
<li>getClass</li>
<li>equals</li>
<li>hashCode</li>
<li>toString</li>
<li>wait</li>
<li>wait(long): 让当前对象进入TIMED_WATING状态</li>
<li>wait(long,int):让当前对象进入TIMED_WATING状态</li>
<li>notify</li>
<li>nofifyAll</li>
<li>clone</li>
<li>finalize</li>
</ol>
<h4 id="静态属性方法和成员属性方法区别"><a href="#静态属性方法和成员属性方法区别" class="headerlink" title="静态属性方法和成员属性方法区别"></a>静态属性方法和成员属性方法区别</h4><p><strong>静态属性和方法属于类Class,而成员属性和方法属于实例化的对象。</strong></p>
<p>静态方法只能使用静态方法和静态属性,不能使用成员属性和方法,<br>因为静态属性和方法在对象还没被实例化的时候就存在了。</p>
<p><strong>简单理解就是不允许一个已存在的事物使用一个不存在的事物。</strong></p>
<h4 id="子类属性与父类属性初始化顺序"><a href="#子类属性与父类属性初始化顺序" class="headerlink" title="子类属性与父类属性初始化顺序"></a>子类属性与父类属性初始化顺序</h4><ol>
<li><p>无论如何,静态数据首先加载,所以先初始化父类静态变量和静态初始化块(静态变量和静态初始化块按源码编写的顺序执行，<br>普通初始化块和普通成员变量也是如此),再初始化子类静态变量和静态初始化块。</p>
</li>
<li><p>普通初始化块和普通成员变量优先于构造方法,所以接下来加载父类的普通初始化块和普通成员变量,再调用父类构造方法。</p>
</li>
<li><p>调用子类普通代码块，普通成员变量和构造方法。</p>
</li>
</ol>
<h4 id="自动拆箱和装箱"><a href="#自动拆箱和装箱" class="headerlink" title="自动拆箱和装箱"></a>自动拆箱和装箱</h4><p>自动拆箱和装箱实际上是Java编译器的一个语法糖。</p>
<p>自动装箱是指: <strong>将基本数据类型转为对应的包装类对象的过程。</strong></p>
<p>自动拆箱是指: <strong>将包装类转为对应的基本数据类型。</strong></p>
<p><strong>自动装箱实际上是调用了包装类对象的valueof方法</strong>,如: Integer.valueof(1)</p>
<p><strong>自动拆箱实际上是调用了包装类的xxxValue方法</strong>,如: Integer.intValue()</p>
<p><strong>在自动装箱的时候,如果包装类允许缓存并且值在缓存的范围内,那么装箱生成的对象会被缓存到常量池中。</strong></p>
<p><strong>Integer,Byte,Short,Long,Character包装类型具有缓存池,<br>而其他三种:Float,Double,Boolean不具有缓存池。</strong></p>
<p>包装类的缓存池缓存的范围基本都为: -128 - 127之间，<br>除了Character的缓存范围为 0 - 127。</p>
<h4 id="String为什么不可变"><a href="#String为什么不可变" class="headerlink" title="String为什么不可变?"></a>String为什么不可变?</h4><p>先说下我的看法:String是Java中最常使用的类没有之一,如果String是可变的,那么会发生非常多数不清的问题。<br>如ip地址,人名,邮箱非常多的敏感数据。<br>如果String是可变的,就会发生安全问题,<br>且字符串常量池也就无从谈起了。</p>
<p>String是不可变的,那么它本质上也是线程安全的。<br><strong>不可变类的缺点就是每个不同的值需要创建一个对象</strong></p>
<p><strong>String 是用final修饰的，保证了String类不能被扩展。<br>String内部的字段是用final修饰的(我的jdk版本是11,String由byte[]实现)，<br>并且没有对外提供修改字段的方法。这也是为什么String不可变的原理。</strong></p>
<h4 id="final关键字的作用"><a href="#final关键字的作用" class="headerlink" title="final关键字的作用"></a>final关键字的作用</h4><ul>
<li><p>被final修饰的类，不能被继承，并且这个类所有的成员方法都为final，不能被重写。</p>
</li>
<li><p>被final修饰的属性变量，不能被修改。如果该变量是基本数据类型的，那么其值在初始化后不能被修改。<br>如果该变量是引用类型的，那么该引用不能再指向其他对象。</p>
</li>
<li><p>被final修饰的方法不能被子类重写。</p>
</li>
</ul>
<h4 id="StringBuilder和StringBuffer区别"><a href="#StringBuilder和StringBuffer区别" class="headerlink" title="StringBuilder和StringBuffer区别"></a>StringBuilder和StringBuffer区别</h4><p><strong>StringBuilder和StringBuffer都是可变的字符串,但是StringBuilder是线程不安全的。</strong></p>
<p>StringBuffer是安全的,因此单线程情况下考虑使用StringBuilder,多线程情况下考虑使用StringBuffer。</p>
<p><strong>他们之间的关系就好比HashMap和HashTable的关系。</strong></p>
<h4 id="equals知识点"><a href="#equals知识点" class="headerlink" title="equals知识点"></a>equals知识点</h4><ul>
<li><p><strong>== 和 equals区别</strong>:</p>
<ul>
<li>==比较的是对象的内存地址,equals比较的是对象的值。<br>因此在Java中比较2个对象的值是否相等使用equals,判断2个对象是否是一个对象,使用==。</li>
</ul>
</li>
<li><p>hashCode方法返回的真是对象内存地址吗? 这个已在对象内存布局部分有讲解，此处就不重复写了。</p>
</li>
<li><p>equals方法重写要求</p>
<ul>
<li><p>自反性: x.equals(x) == true 永远成立</p>
</li>
<li><p>非空性: x.equals(null) == false 永远成立</p>
</li>
<li><p>对称性: 如果 x.equals(y) == true , 那 y.equals(x)== true  </p>
</li>
<li><p>传递性: 如果 x.equals(y) == true,并且 y.equals(z) == true,那么一定满足x.equals(z) == true</p>
</li>
<li><p>一致性: 如果x.equals(y) == true , 那么只要x和y的值不变,那么x.equals(y) == true 永远成立</p>
</li>
</ul>
</li>
<li><p>为什么重写equals方法一定要重写hashcode方法?</p>
<p>在普通环境下(不涉及hash表),equals方法和hashcode方法一毛钱关系没有的,<br>此时重写equals但不重写hashcode是没有关系的。<br>但<strong>当使用map,set这些散列表时,<br>它们会根据对象的hashcode来计算对象在散列表中的位置的。</strong><br>试想下,如果2个对象的值相等,但是由于它们是2个对象,hashcode却不相等。<br>那么即使放入map,set(map)仍会存在重复数据。</p>
</li>
</ul>
<h4 id="深拷贝与浅拷贝"><a href="#深拷贝与浅拷贝" class="headerlink" title="深拷贝与浅拷贝"></a>深拷贝与浅拷贝</h4><p><strong>深拷贝: 拷贝所有的内容,除了基本数据类型的变量复制一份,连引用类型的的对象也复制一份。</strong></p>
<p><strong>浅拷贝: 复制基本数据类型的变量,对于引用类型的变量,直接返回这个引用本身。</strong></p>
<h4 id="IO流分类"><a href="#IO流分类" class="headerlink" title="IO流分类"></a>IO流分类</h4><ol>
<li><p>按照流的流向,分为:输入流和输入流。</p>
</li>
<li><p>按照操作单元,分为:字节流和字符流。</p>
</li>
</ol>
<h4 id="使用字节流还是字符流"><a href="#使用字节流还是字符流" class="headerlink" title="使用字节流还是字符流?"></a>使用字节流还是字符流?</h4><p>考虑通用性,应该使用字节流。<br>如果只是文本文件的操作,可以考虑使用字符流。</p>
<h4 id="BigDecimal"><a href="#BigDecimal" class="headerlink" title="BigDecimal"></a>BigDecimal</h4><p>BigDecimal是Java中表示大浮点数的类型。</p>
<p>在Java中,如果遇到浮点数的判断,可以使用BigDecimal来做计算,<br>因为如果使用普通数据类型很可能会发生精度丢失的情况,这个时候的结果可能会出乎意料之外.</p>
<h4 id="Java异常体系结构"><a href="#Java异常体系结构" class="headerlink" title="Java异常体系结构"></a>Java异常体系结构</h4><p>在Java中,异常分为 Exception和Error,这2个类都继承自Throwable。</p>
<ul>
<li><p>Exception: Exception异常是程序本身可以处理的。Exception 分为运行时异常(RuntimeException)和<br>非运行时异常(CheckedException)。</p>
<ul>
<li><p>RuntimeException: RuntimeException(运行时异常)是在程序运行时可能会发生的异常,如NullPointException,<br>这类异常往往是不可预料的,编译器也不会要求你手动try catch或throws。</p>
</li>
<li><p>CheckedException: CheckedException(非运行时异常)是RuntimeException以外的异常,如IOException，<br>这类异常要求必须显示的try catch或throws ， 如果不处理,那么编译就不会通过。</p>
</li>
</ul>
</li>
<li><p>Error: Error错误是程序无法处理的,表示程序或JVM出现了很严重的，无法解决问题。</p>
</li>
</ul>
<h4 id="Comparable和Comparator"><a href="#Comparable和Comparator" class="headerlink" title="Comparable和Comparator"></a>Comparable和Comparator</h4><ul>
<li><p>Comparable: 自然排序接口。实现了它的类意味着就支持排序。</p>
</li>
<li><p>Comparator: 外部比较器。无需让需要排序的对象实现排序逻辑，而是根据Comparator定义的逻辑来排序。<br>Comparator相较于Comparable更加的灵活。</p>
</li>
</ul>
<h4 id="为什么要慎用-Arrays-asList"><a href="#为什么要慎用-Arrays-asList" class="headerlink" title="为什么要慎用 Arrays.asList()?"></a>为什么要慎用 Arrays.asList()?</h4><p><strong>因为Arrays.asList这个方法返回的根本就不是我们期盼的ArrayList,<br>而是Arrays类内部实现的ArrayList,这个内部类只支持访问和set操作,<br>并不支持remove,add,clear等修改操作。</strong></p>
<h4 id="Java中引用的类型"><a href="#Java中引用的类型" class="headerlink" title="Java中引用的类型"></a>Java中引用的类型</h4><p>Java中引用类型总共有四种: 强引用，软引用，弱引用，虚引用。</p>
<ul>
<li><p>强引用(Strong Reference): Java程序中绝大部分都是强引用，一般使用new关键字创建的对象就是强引用。<br>只要强引用存在，强引用的对象就不会被回收，除非不可达(参考jvm部分)</p>
</li>
<li><p>软引用(Soft Reference): 软引用一般不会回收，但是当堆内存不够的时候，<br>比如几乎快要发生OOM的时候，就会发生回收掉软引用对象。</p>
</li>
<li><p>弱引用(Weak Reference): 只要垃圾回收开始，就会回收掉弱引用的对象</p>
</li>
<li><p>虚引用(Phantom Reference,又称幽灵引用): 和其他几种引用不同，虚引用不决定对象的生命周期，<br>它在任何时候都可能被回收掉。</p>
</li>
</ul>
<hr>
<h2 id="对象在内存中的布局-64位"><a href="#对象在内存中的布局-64位" class="headerlink" title="对象在内存中的布局(64位)"></a>对象在内存中的布局(64位)</h2><p>对象在内存中的布局,在32位和64位上的实现也是不同的，以我的机器为例(64位)</p>
<p><strong>对象在内存中由 对象头,实例数据,对齐填充三部分组成。</strong></p>
<p>其中<strong>实例数据和对齐填充是不固定的</strong>，下面会讲到。</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/对象在内存中的布局.png" alt="对象内存布局" title="">
                </div>
                <div class="image-caption">对象内存布局</div>
            </figure>
<p><strong>可以使用openjdk-jol工具查看对象的内存布局</strong></p>
<h3 id="对象头"><a href="#对象头" class="headerlink" title="对象头"></a>对象头</h3><p>在hotspot虚拟机中的对象头由2部分组成(<strong>如果是数组,对象头还会保存数组长度</strong>):<br>mark 和 metadata(包括klass* , compressed_klass)(见oop.hpp文件)</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/对象头的markword组成1.png" alt="对象头组成1" title="">
                </div>
                <div class="image-caption">对象头组成1</div>
            </figure>
<p>下面是mark/markword的组成(见:markOop.hpp头文件):</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/对象头的markword组成2.png" alt="对象头组成2" title="">
                </div>
                <div class="image-caption">对象头组成2</div>
            </figure>
<p>对象处于每种状态时的锁标志位都不同(见:markOop.hpp头文件):</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/对象头的markword组成3.png" alt="对象头组成3" title="">
                </div>
                <div class="image-caption">对象头组成3</div>
            </figure>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/对象头的markword组成4.png" alt="对象头组成4" title="">
                </div>
                <div class="image-caption">对象头组成4</div>
            </figure>
<h4 id="markword和metadata"><a href="#markword和metadata" class="headerlink" title="markword和metadata"></a>markword和metadata</h4><p>Mark Word(mark)组成:</p>
<table>
<thead>
<tr>
<th style="text-align:center">锁状态</th>
<th style="text-align:center">锁标志</th>
<th style="text-align:center">markword组成</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:center">无锁</td>
<td style="text-align:center">01</td>
<td style="text-align:center">由hashcode,分代年龄,是否偏向锁(1位),锁标志位组成</td>
</tr>
<tr>
<td style="text-align:center">偏向锁</td>
<td style="text-align:center">01</td>
<td style="text-align:center">由偏向线程的ID,偏向时间戳(epoch),是否偏向锁(1位),分代年龄,锁标志位组成</td>
</tr>
<tr>
<td style="text-align:center">轻量级锁</td>
<td style="text-align:center">00</td>
<td style="text-align:center">由指向栈中锁的记录和锁标志位组成</td>
</tr>
<tr>
<td style="text-align:center">膨胀锁</td>
<td style="text-align:center">10</td>
<td style="text-align:center">由指向锁的指针和锁标志位组成</td>
</tr>
<tr>
<td style="text-align:center">GC</td>
<td style="text-align:center">11</td>
<td style="text-align:center">无数据</td>
</tr>
</tbody>
</table>
<p>Klass Pointer /  Compressed Klass: <strong>Klass Pointer是指向对象类型的指针，指针指向对象的类元数据。</strong><br>jvm通过klass pointer判断对象属于哪个类。<br>在64位的jvm实现中，Klass Pointer的长度为64bit(32位系统,<br>指针为32bit)，也就意味着,64位系统比32位的系统占用更多内存。</p>
<p>所以<strong>jvm提供了压缩指针(Compressed Klass)来节省空间，在64位系统下，压缩指针是默认开启的，<br>可以使用-XX:-UseCompressedOops来关闭指针压缩。</strong></p>
<h4 id="实例数据"><a href="#实例数据" class="headerlink" title="实例数据"></a>实例数据</h4><p>实例数据存储着对象在程序中被定义的各个字段的数据,也就是对象的字段的<br>数据。<strong>如果一个类没有字段，也就不存在实例数据，所以这是它不固定的原因。</strong></p>
<h4 id="对齐填充"><a href="#对齐填充" class="headerlink" title="对齐填充"></a>对齐填充</h4><p><strong>Java对象的小必须是8字节的倍数</strong>,像13,15这种非8的倍数的对象的大小,<br>不足或多余的部分就要使用对齐填充数据补齐。<br><strong>如果Java对象大小正好是8的倍数,那么就无需对齐填充数据。</strong></p>
<h3 id="jol工具查看对象布局"><a href="#jol工具查看对象布局" class="headerlink" title="jol工具查看对象布局"></a>jol工具查看对象布局</h3><figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">&lt;!--可用此工具查看对象内存布局--&gt;</span></span><br><span class="line"> <span class="tag">&lt;<span class="name">dependency</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">groupId</span>&gt;</span>org.openjdk.jol<span class="tag">&lt;/<span class="name">groupId</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">artifactId</span>&gt;</span>jol-core<span class="tag">&lt;/<span class="name">artifactId</span>&gt;</span></span><br><span class="line">     <span class="tag">&lt;<span class="name">version</span>&gt;</span>0.10<span class="tag">&lt;/<span class="name">version</span>&gt;</span></span><br><span class="line"> <span class="tag">&lt;/<span class="name">dependency</span>&gt;</span></span><br></pre></td></tr></table></figure>
<p>相信各位同学可能还是对上面的概念有点迷糊，那就可以使用jol工具来查看一下<br>对象的真实布局，在实践之前，请各位同学带着几个问题看下面的内容:</p>
<ul>
<li><p>hashCode方法返回的真是对象内存地址吗?</p>
</li>
<li><p>hashcode真实存在吗?</p>
</li>
</ul>
<h4 id="查看对象内存布局"><a href="#查看对象内存布局" class="headerlink" title="查看对象内存布局"></a>查看对象内存布局</h4><p>一下是我自己的一个测试demo，详解了jol的使用:</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/jol工具查看对象内存布局1.png" alt="jol工具查看对象内存布局1" title="">
                </div>
                <div class="image-caption">jol工具查看对象内存布局1</div>
            </figure>
<p>以上可以看到jol工具很直观的给我们展现了对象的内存布局，<br>但是在对象的markword之中，我们并没有看到hashcode的值，<br>难道对象不存在hashcode吗？</p>
<h4 id="hashcode"><a href="#hashcode" class="headerlink" title="hashcode"></a>hashcode</h4><p>上一个测试在打印对象内存布局之前，我并没有调用对象的hashcode方法，<br>相信各位同学也注意到了，我把那2行代码注释掉了。</p>
<p>打开那2行注释再运行看看:</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/jol工具查看对象内存布局2.png" alt="jol工具查看对象内存布局2" title="">
                </div>
                <div class="image-caption">jol工具查看对象内存布局2</div>
            </figure>
<p>我们发现，在调用hashcode方法后，对象的hashcode的值与打印结果完全一致，<br>到这里可以初步猜想:</p>
<p><strong>hashcode的值也是不固定存在的。</strong></p>
<p><strong>在没有调用对象的hashcode方法之前，对象不存在hashcode。</strong></p>
<p><strong>当调用完对象的hashcode之后，jvm就把生成的hashcode值赋予了对象的markword之中。</strong></p>
<h4 id="对象的hashcode返回的是对象的内存地址吗"><a href="#对象的hashcode返回的是对象的内存地址吗" class="headerlink" title="对象的hashcode返回的是对象的内存地址吗?"></a>对象的hashcode返回的是对象的内存地址吗?</h4><p><strong>在hotspot中，hashcode返回的不完全是地址</strong><br>(见：hotspot的/src/share/vm/runtime/synchronizer.cpp):</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/hashcode方法源码.png" alt="hashcode方法源码" title="">
                </div>
                <div class="image-caption">hashcode方法源码</div>
            </figure>
<p>可以看到hashcode有多种返回策略:随机数，自增长序列，关联地址等多种方式。</p>
<hr>
<h2 id="线程并发-JUC-AQS-CAS"><a href="#线程并发-JUC-AQS-CAS" class="headerlink" title="线程并发(JUC,AQS,CAS)"></a>线程并发(JUC,AQS,CAS)</h2><h3 id="多线程"><a href="#多线程" class="headerlink" title="多线程"></a>多线程</h3><h4 id="进程和线程"><a href="#进程和线程" class="headerlink" title="进程和线程"></a>进程和线程</h4><p><strong>进程与线程最主要的区别是它们是操作系统管理资源的不同方式的体现。</strong><br>准确来说进程与线程属于衍生关系。<br>进程是操作系统执行程序的一次过程,在这个过程中可能会产生多个线程。</p>
<blockquote>
<p>比如在使用QQ时，有窗口线程，<br>文字发送的线程，语音输入的线程，可能不是很恰当，但是就是这个意思。</p>
</blockquote>
<p><strong>在Java中，一个进程产生的多个线程共享这个进程内的堆，方法区等共享资源，<br>每个线程又有自己的程序计数器，虚拟机栈，本地方法栈。</strong></p>
<blockquote>
<p><strong>由于系统在线程之间的切换比在进程之间的切换更高效率，所以线程也被成为轻量级进程。</strong></p>
</blockquote>
<h4 id="并发和并行"><a href="#并发和并行" class="headerlink" title="并发和并行"></a>并发和并行</h4><ol>
<li><p>并发: 多个线程任务被一个cpu轮流执行。注意，这里并不是规定一个cpu，多个cpu也是可以的。<br><strong>并发主要强调的是cpu有处理多个任务的能力。</strong></p>
</li>
<li><p>并行:多个线程被多个cpu同时执行。这里也并不是规定要多个cpu，一个cpu也是可以的，<br>只要你的cpu能在同一时刻处理多任务。<strong>并行强调的是拥有同时处理多任务的能力。</strong></p>
</li>
</ol>
<h4 id="多线程的利弊"><a href="#多线程的利弊" class="headerlink" title="多线程的利弊"></a>多线程的利弊</h4><ul>
<li><p>利:线程可以比作轻量级的进程，现在是多核cpu时代，意味着多个线程可以被通过cpu同时运行(并行)，<br>这就减少了上下文的开销，如果可以利用好多线程，那么就可以编写出高并发的程序。</p>
</li>
<li><p>弊:虽然线程带来的好处很多，但是并发编程并不容易，如果控制不好线程，<br>那么就可能造成死锁，资源闲置，内存泄露等问题。</p>
</li>
</ul>
<h4 id="什么是上下文切换"><a href="#什么是上下文切换" class="headerlink" title="什么是上下文切换?"></a>什么是上下文切换?</h4><p>cpu是采用时间片的轮转制度，在多个线程之间来回切换运行的。<br>当cpu切换到另一个线程的时候，它会先保存当前线程执行的状态，<br>以便在下次切换回来执行时，可以重新加载状态，继续运行。<br><strong>从保存状态再到重新加载回状态的这个过程就叫做上下文切换。</strong></p>
<h4 id="线程的优先级"><a href="#线程的优先级" class="headerlink" title="线程的优先级"></a>线程的优先级</h4><p>在Java中可以通过Thread类的setPriority方法来设置线程的优先级，<br>虽然可以通过这样的方式来设置线程的优先级，但是线程执行的先后顺序并不依赖与线程的优先级。<br>换句话说就是，<strong>线程的优先级不保证线程执行的顺序。</strong></p>
<h4 id="线程的几种状态"><a href="#线程的几种状态" class="headerlink" title="线程的几种状态"></a>线程的几种状态</h4><p>见:jdk Thread类源码中的state枚举类</p>
 <figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED</span><br></pre></td></tr></table></figure>
<h4 id="sleep方法和wait方法"><a href="#sleep方法和wait方法" class="headerlink" title="sleep方法和wait方法"></a>sleep方法和wait方法</h4><ol>
<li><p>sleep方法是Thread类的方法，而wait方法是Object类的方法</p>
</li>
<li><p>sleep方法会<strong>使当前线程让出cpu的调度资源</strong>，从而让其他线程有获得被执行的机会，<br><strong>但是并不会让当前线程释放锁对象。</strong><br>而wait方法是<strong>让当前线程释放锁并进入wait状态，</strong><br>不参与获取锁的争夺，从而让其他等待资源的线程有机会获取锁，<br>只有当其他线程调用notify或notifyAll方法是，被wait的线程才能重新与其他线程一起争夺资源。<br>被wait的线程才能重新与其他线程一起争夺资源。</p>
</li>
</ol>
<h4 id="stop-suspend-resume等方法为什么会被遗弃"><a href="#stop-suspend-resume等方法为什么会被遗弃" class="headerlink" title="stop,suspend,resume等方法为什么会被遗弃"></a>stop,suspend,resume等方法为什么会被遗弃</h4><ul>
<li><p>stop: stop方法被弃用很好理解，因为stop方法是强行终止线程的执行，<br>不管线程的run方法是否执行完，资源是否释放完，它都会终止线程的运行，并释放锁。<br>这在设计上就不合理，不说资源控制的问题，当线程正在执行任务的时候，线程突然就被stop了，<br>这根本上就是不被允许的。  </p>
</li>
<li><p>suspend和resume: suspend方法用于阻塞一个线程,但并不释放锁，<br>而resume方法的作用只是为了恢复被suspend的线程。<br>假设A，B线程都争抢同一把锁，A线程成功的获得了锁，<br>然后被suspend阻塞了，却并没有释放锁，它需要其他线程来唤醒，<br>但此时B线程需要获得这把锁才能唤醒A，所以此时就陷入了死锁。</p>
</li>
</ul>
<h4 id="interrupt-interrupted-isInterrupted方法区别"><a href="#interrupt-interrupted-isInterrupted方法区别" class="headerlink" title="interrupt,interrupted,isInterrupted方法区别"></a>interrupt,interrupted,isInterrupted方法区别</h4><ul>
<li><p>interrupt: 这个方法并不是中断当前线程，而是给当前线程设置一个中断状态。</p>
</li>
<li><p>isInterrupted: 当线程调用interrupt方法后，线程就有了一个中断状态，<br>而使用isInterrupted方法就可以检测到线程的中断状态。</p>
</li>
<li><p>interrupted: 这个方法用于清除interrupt方法设置的中断状态。<br>如果一个线程之前调用了interrupt方法设置了中断状态，<br>那么interrupted方法就可以清除这个中断状态。           </p>
</li>
</ul>
<h4 id="join方法"><a href="#join方法" class="headerlink" title="join方法"></a>join方法</h4><p>join方法的作用是让指定线程加入当线程执行。</p>
<p>假如在main方法里面创建一个线程A执行，并调用A的join方法，<br>那么当前线程就是main，指定的A线程就会在main之前执行，<br>等A执行完后，才会继续执行main。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">public static void main(String[] args) throws Exception</span><br><span class="line">&#123;</span><br><span class="line"></span><br><span class="line">    Thread a = new Thread(()-&gt;</span><br><span class="line">    &#123;</span><br><span class="line">        try</span><br><span class="line">        &#123;</span><br><span class="line">            TimeUnit.SECONDS.sleep(1);</span><br><span class="line">            </span><br><span class="line">        &#125;catch (Exception e)&#123;&#125;</span><br><span class="line"></span><br><span class="line">        System.out.println(&quot;thread join&quot;);</span><br><span class="line">    &#125;);</span><br><span class="line">    a.start();</span><br><span class="line"></span><br><span class="line">    //a会在main线程之前执行</span><br><span class="line">    a.join();</span><br><span class="line"></span><br><span class="line">    System.out.println(&quot;main&quot;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p><strong>join方法的底层是wait方法，调用A线程(子线程)的join方法实际上是让main线程wait，<br>等A线程执行完后，才能继续执行后面的代码。</strong></p>
<h4 id="yield方法"><a href="#yield方法" class="headerlink" title="yield方法"></a>yield方法</h4><p>yield属于Thread的静态方法，<br>它的作用是让当前线程让出cpu调度资源。</p>
<p>yield方法其实就和线程的优先级一样，你虽然指定了，<br>但是最后的结果不由得你说了算，<br><strong>即使调用了yield方法，最后仍然可能是这个线程先执行，<br>只不过说别的线程可能先执行的机会稍大一些。</strong></p>
<h3 id="并发"><a href="#并发" class="headerlink" title="并发"></a>并发</h3><h4 id="synchronized"><a href="#synchronized" class="headerlink" title="synchronized"></a>synchronized</h4><p>synchronized是jdk提供的jvm层面的同步机制。<br><strong>它解决的是多线程之间访问共享资源的同步问题,它保证了<br>在被它修饰的方法或代码块同一时间只有一个线程执行。</strong></p>
<p>java6之前的synchronized属于重量锁,性能较差,<br>它的原理是基于操作系统的Mutex Lock互斥量实现的。</p>
<p><strong>因为java线程是映射到操作系统的线程之上的,<br>所以暂停或唤醒线程都需要Java程序从用户态转换为内核态,这段转换时间消耗较长。</strong></p>
<blockquote>
<p>java6之后jvm团队对synchronized做出了非常大的优化。</p>
</blockquote>
<h4 id="synchronized底层原理"><a href="#synchronized底层原理" class="headerlink" title="synchronized底层原理"></a>synchronized底层原理</h4><p>先看我编写的一段测试代码:</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/synchronized底层原理1.png" alt="synchronized底层原理1" title="">
                </div>
                <div class="image-caption">synchronized底层原理1</div>
            </figure>
<p>使用 javap -c 指令反编译 class文件后的 <strong>字节码指令</strong> 如下</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/synchronized底层原理2.png" alt="synchronized底层原理2" title="">
                </div>
                <div class="image-caption">synchronized底层原理2</div>
            </figure>
<blockquote>
<p>可以清楚的看到,在进入synchronized的时候，底层字节码编译出来的指令为<br><strong>monitorenter</strong>,在执行完同步代码块后又有一个<strong>monitorexit</strong>指令.</p>
</blockquote>
<p>想了解synchronized究竟是如何实现的,可以直接进入openjdk:src/share/vm/runtime 目录,这个目录存放的是hotspot虚拟机在运行时<br>所需的代码.</p>
<blockquote>
<p>可以直接锁定其中的 objectMonitor.cpp源文件和objectMonitor.hpp头文件.<br>看到这2个文件，相信各位同学应该就知道，这个就是synchronized锁对象的monitor，它也是<br>一个对象,不过它是一个c++对象(见:objectMonitor.hpp头文件):</p>
</blockquote>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/synchronized底层原理3.png" alt="synchronized底层原理3" title="">
                </div>
                <div class="image-caption">synchronized底层原理3</div>
            </figure> 
<p><strong>其实真正的锁应该是这个monitor,synchronized锁的那个对象起到的只是关联monitor的作用。<br>只不过我们身在java层面，无法感知到monitor的作用，所以才称synchronized的锁对象为锁。</strong></p>
<p>以下是monitorenter指令执行过程(见 InterpreterRuntime.cpp):</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/synchronized底层原理4.png" alt="synchronized底层原理4" title="">
                </div>
                <div class="image-caption">synchronized底层原理4</div>
            </figure>
<p>PS:本来想真正弄清楚fast_enter(偏向锁的实现),slow_enter(轻量级锁实现)和inflate(膨胀锁实现)<br>的,无奈暂时看不太懂cpp源码，但是有的地方是可以根据语义来推断的。</p>
<p>这里做一个总结吧,这个总结可能不太准确，但大致是这样的:<br><strong>每次执行monitorenter指令的时候,是将当前synchronized锁对象<br>关联的</strong>monitor<strong>的_recursions加1,<br>执行monitorexit指令的时候,将当前object对象关联的</strong>monitor<strong>的_recursions减1,<br>当_recursions为0的时候，就说明线程不再持有锁对象。</strong></p>
<p><strong>如果熟悉AQS原理的同学就知道在AQS内部，<br>有一个被volatile修饰state变量，<br>这个state变量就是AQS的核心，<br>state变量的作用类比到此处就是monitor计数器的作用。</strong></p>
<h4 id="synchronized-使用方法"><a href="#synchronized-使用方法" class="headerlink" title="synchronized 使用方法"></a>synchronized 使用方法</h4><ol>
<li><p>修饰静态方法: 修饰静态方法是给类加锁,会作用于所有对象,因为静态方法属于类,<br>而不属于对象,不管有多少个对象,static方法都是共享的。</p>
</li>
<li><p>修饰实例方法: 修饰实例方法是给对象加锁,会作用于当前类的实例对象。</p>
</li>
<li><p>修饰代码块: 修饰代码块,根据代码块给定的对象加锁,线程想要进入代码块,只能获取指定的对象的锁。</p>
</li>
</ol>
<h4 id="Synchronized和ReentrantLock的区别"><a href="#Synchronized和ReentrantLock的区别" class="headerlink" title="Synchronized和ReentrantLock的区别"></a>Synchronized和ReentrantLock的区别</h4><ul>
<li><p>Synchronized是基于JVM层面的同步机制;而ReentrantLock是基于Java API层面提供的同步机制。</p>
</li>
<li><p>Synchronized和Reentrantlock都属于可重入锁。</p>
</li>
<li><p>ReentrantLock提供了比Synchronized更高级的功能:</p>
<ul>
<li><p>公平锁</p>
</li>
<li><p>更方便的线程间的通信(Condition)</p>
</li>
<li><p>等待可中断(在线程等待获取锁的时候可以被中断) </p>
</li>
</ul>
</li>
</ul>
<h4 id="乐观锁"><a href="#乐观锁" class="headerlink" title="乐观锁"></a>乐观锁</h4><p>乐观锁对共享的数据很乐观，认为不会发生线程安全的问题，从而不给数据加锁。<br>乐观锁适用于读多写少的环境。常见的例子就是mysql的更新使用version控制。</p>
<p><strong>CAS属于乐观锁。</strong></p>
<h4 id="悲观锁"><a href="#悲观锁" class="headerlink" title="悲观锁"></a>悲观锁</h4><p>悲观锁对共享的数据很悲观，认为无论什么时候都有可能发生线程安全的问题，<br>所以在每次读写数据的时候都会加锁。</p>
<p><strong>Synchronized属于悲观锁。</strong></p>
<h4 id="独占锁"><a href="#独占锁" class="headerlink" title="独占锁"></a>独占锁</h4><p>锁一次只能被一个线程占有使用。</p>
<p>Synchronized和ReetrantLock都是独占锁。</p>
<h4 id="共享锁"><a href="#共享锁" class="headerlink" title="共享锁"></a>共享锁</h4><p>锁可以被多个线程持有。</p>
<p>对于ReentrantReadWriteLock而言,它的读锁是共享锁,写锁是独占锁。</p>
<h4 id="公平锁"><a href="#公平锁" class="headerlink" title="公平锁"></a>公平锁</h4><p>公平锁指根据线程在队列中的优先级获取锁,比如线程优先加入阻塞队列,那么线程就优先获取锁。</p>
<h4 id="非公平锁"><a href="#非公平锁" class="headerlink" title="非公平锁"></a>非公平锁</h4><p>非公平锁指在获取锁的时候,每个线程都会去争抢,并且都有机会获取到锁,无关线程的优先级。</p>
<h4 id="可重入锁-递归锁"><a href="#可重入锁-递归锁" class="headerlink" title="可重入锁(递归锁)"></a>可重入锁(递归锁)</h4><p>一个线程获取到锁后,如果继续遇到被相同锁修饰的资源,那么可以继续获取该锁。</p>
<p>Synchronized和Reentrantlock都是可重入锁。</p>
<h4 id="偏向锁"><a href="#偏向锁" class="headerlink" title="偏向锁"></a>偏向锁</h4><p>在线程获取偏向锁的时候,<br>jvm会判断锁对象MarkWord里偏向线程的ID是否为当前线程ID。</p>
<p>如果是,则说明当前锁对象处于偏向状态。</p>
<p>如果不是,则jvm尝试CAS把对象的MarkWord的偏向线程ID设置为当前线程ID,</p>
<p>如果设置成功,那么对象偏向当前线程，并将当对象的锁标志位改为01。</p>
<p>如果设置失败，则说明多线程竞争，将撤销偏向锁，升级为轻量级锁。</p>
<p><strong>偏向锁适用于单线程无锁竞争环境(单线程环境)。</strong></p>
<p>hotspot偏向锁实现(faster_enter):<br><figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/偏向锁实现.png" alt="偏向锁实现" title="">
                </div>
                <div class="image-caption">偏向锁实现</div>
            </figure></p>
<h4 id="轻量级锁"><a href="#轻量级锁" class="headerlink" title="轻量级锁"></a>轻量级锁</h4><p>在线程获取对象锁时，jvm首先会判断对象是否为无锁状态(无锁状态标志位为01)。</p>
<p>如果对象是无锁状态，那么将在线程的栈帧中开辟一块空间用于存储对象的MarkWord，<br>然后将对象的MarkWord复制到栈帧空间去，并使用CAS更新对象的MarkWord为指向<br>线程栈帧的指针。</p>
<p>如果更新成功，那么当前线程获取锁成功，并修改对象的MarkWord标志位<br>为 00 。</p>
<p>如果更新失败，那么jvm会判断对象的MarkWord是否已经指向线程的栈帧。</p>
<p>如果已经指向，那么线程直接执行同步代码。否则，说明多个线程竞争，将inflate为重量级锁。</p>
<p><strong>轻量级锁适用于多线程无锁竞争环境(多线程轮流执行,并不会发生冲突)。</strong></p>
<p>hotspot轻量级锁实现(slow_enter):<br><figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/轻量级锁实现.png" alt="轻量级锁实现" title="">
                </div>
                <div class="image-caption">轻量级锁实现</div>
            </figure>   </p>
<h4 id="自旋锁"><a href="#自旋锁" class="headerlink" title="自旋锁"></a>自旋锁</h4><p>在争夺锁的过程中，线程不会停止获取锁，而是通过CAS不断的判断线程是否符合获取锁的条件。</p>
<p><strong>AQS获取锁的核心就是CAS。</strong></p>
<h4 id="自适应自旋锁"><a href="#自适应自旋锁" class="headerlink" title="自适应自旋锁"></a>自适应自旋锁</h4><p>自旋锁意味着线程会不断的消耗cpu资源，短时间还行，长时间就意味着而资源的浪费。<br>所以自适应自旋锁会有一个自旋的生命周期,过了这个生命周期,线程将不再自旋。</p>
<p>网上有文章说这个生命周期依据前一个线程的自旋时间来决定，但是我暂且没有找到相关资料，不敢妄自揣测。</p>
<h4 id="锁消除"><a href="#锁消除" class="headerlink" title="锁消除"></a>锁消除</h4><p><strong>锁消除属于Java编译器对程序的一种优化机制。</strong><br>锁消除是指当JVM的JIT编译器检测出一些已经加锁的代码不可能出现共享的数据存在竞争的问题，<br>会消除这样的锁。<strong>锁消除的依据来源于逃逸分析算法。</strong><br>如果判断到一段代码，在堆上的数据不会逃逸出去被其他线程访问到，<br>那么就把它们当做栈上的数据，为线程私有的，自然无需同步加锁。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">    //每次线程进入此方法，创建的都是不同的StringBuffer临时对象,</span><br><span class="line">    //也就是说 StringBuffer 临时对象不会逃出方法t,作用于外部,</span><br><span class="line">    //所以根本不存在线程之间的竞争，那么JIT在编译时就会消除append方法的锁</span><br><span class="line">    public String t(String s1, String s2,String s3)</span><br><span class="line">    &#123;</span><br><span class="line">        return new StringBuffer().append(s1).append(s2)</span><br><span class="line">                    .append(s3).toString();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">````       </span><br><span class="line">       </span><br><span class="line">#### 锁粗化 </span><br><span class="line">当虚拟机检测出一系列连续的操作都对同一个连续加锁，</span><br><span class="line">那么它会把加锁的返回扩大至整个操作的序列的外部，保证只加锁一次。</span><br><span class="line"></span><br><span class="line">````text</span><br><span class="line"></span><br><span class="line">    public String t()</span><br><span class="line">    &#123; </span><br><span class="line">        StringBuffer stringBuffer = new StringBuffer();</span><br><span class="line">        for (int i = 0 ; i &lt; 100 ; ++i)</span><br><span class="line">        &#123;</span><br><span class="line">            //append方法执行一百次,难道加100次锁?</span><br><span class="line">           stringBuffer.append(i);</span><br><span class="line">        &#125;</span><br><span class="line">        return stringBuffer.toString();</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    //t方法经过优化后可能如下:</span><br><span class="line">    public String t()</span><br><span class="line">    &#123; </span><br><span class="line">        StringBuffer stringBuffer = new StringBuffer();</span><br><span class="line">        //把synchronized方法提升到for循环面，这样就避免了每次</span><br><span class="line">        //append方法的同步</span><br><span class="line">        synchronized (stringBuffer)</span><br><span class="line">        &#123;</span><br><span class="line">           for (int i = 0 ; i &lt; 100 ; ++i)</span><br><span class="line">           &#123;</span><br><span class="line">               stringBuffer.append(i);</span><br><span class="line">           &#125;</span><br><span class="line">        &#125;</span><br><span class="line">        return stringBuffer.toString();</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<h4 id="死锁"><a href="#死锁" class="headerlink" title="死锁"></a>死锁</h4><p><strong>死锁是指多个进程在执行过程中,循环等待彼此占有的资源而导致程序的无限期的阻塞的情况。</strong></p>
<p>产生死锁的条件:</p>
<ol>
<li>互斥条件: 一个资源在一段时间内只能被一个进程所持有。</li>
<li>不可抢占条件: 进程所持有的资源只能由进程自己主动释放,其他资源的申请者不能向进程持有者抢夺资源。</li>
<li>占有且申请条件: 进程已经持有一个资源后,又申请其他资源,但是其他资源已被其他线程所占有。</li>
<li>循环等待条件: 在条件3之上,进程1有进程2需要申请的资源,进程2有进程1需要申请的资源。那么这2个线程<br>不停等待彼此持有的资源,又不能释放已拥有的资源,陷入循环等待。</li>
</ol>
<p>死锁:</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/死锁.png" alt="死锁" title="">
                </div>
                <div class="image-caption">死锁</div>
            </figure>
<h4 id="如何避免死锁"><a href="#如何避免死锁" class="headerlink" title="如何避免死锁?"></a>如何避免死锁?</h4><p>只要打破死锁产生的4个条件之一就行,但是真正能够被打破的条件只有第3和第4个条件。<br>因为第1和第2个条件都是锁的必要条件。</p>
<p>所以有如下解决死锁的方案:</p>
<ul>
<li><p>可以打破第3个条件: <strong>实现资源的有序分配。</strong> </p>
</li>
<li><p>可以打破第4个条件: <strong>设置等待超时时间。</strong></p>
</li>
</ul>
<h3 id="volatile"><a href="#volatile" class="headerlink" title="volatile"></a>volatile</h3><p>volatile是JVM提供的轻量级的线程同步机制。它可以保证内存的可见性，禁止指令重排序。<br>但是volatile，并不能保证数据的原子性，所以它不合适作为线程同步的工具。</p>
<h4 id="volatile保证内存的可见性"><a href="#volatile保证内存的可见性" class="headerlink" title="volatile保证内存的可见性"></a>volatile保证内存的可见性</h4><p>可见性是指一个线程的对于共享数据的修改对其他线程是可见的。<br>jvm的内存模型是: <strong>线程总是从主内存读取变量到工作内存，然后在工作内存中进行修改，<br>在修改完后再把数据同步到主内存中。</strong><br>如果多个线程同时读取了一个变量到各自的内存中，其中一个线程对变量进行了修改，并同步回了主内存，<br>但其它线程仍然使用的是原来的旧值，这就造成了数据的不一致。</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/Java内存模型.png" alt="Java内存模型" title="">
                </div>
                <div class="image-caption">Java内存模型</div>
            </figure>
<p>解决这个问题的办法就是给变量加上volatile关键字修饰。<br>volatile使得被它修饰的变量在被线程修改后，那么线程就需要把修改后的变量重新同步到主内存，<br>且其他线程每次使用这个变量，都需要从主内存读取。</p>
<h4 id="volatile禁止指令重排序"><a href="#volatile禁止指令重排序" class="headerlink" title="volatile禁止指令重排序"></a>volatile禁止指令重排序</h4><p>指令重排序是编译器和cpu为了程序的高效运行的一种优化手段,<br><strong>指令重排序只能保证程序执行的结果是正确的，但是无法保证程序指令运行的顺序是否与代码的顺序一致,<br>volatile就禁止了这种重排序。</strong></p>
<p>比如: </p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">1. int a = 1;</span><br><span class="line">2. int b = 3;</span><br><span class="line">3. int c = a + b;</span><br></pre></td></tr></table></figure>
<p>上面的代码在编译后,指令执行的顺序可能有:<br>1,2,3和2,1,3<br>这样程序实际执行的顺序可能与代码的顺序不符,但并不会影响程序最终的结果。</p>
<h4 id="volatile如何禁止指令重排序的"><a href="#volatile如何禁止指令重排序的" class="headerlink" title="volatile如何禁止指令重排序的?"></a>volatile如何禁止指令重排序的?</h4><p><strong>volatile通过提供内存屏障来防止指令重排序。<br>java内存模型会在每个volatile写操作前后都会插入store指令，将工作内存中的变量同步回主内存。<br>在每个volatile读操作前后都会插入load指令，从主内存中读取变量。</strong></p>
<h4 id="volatile不保证原子性"><a href="#volatile不保证原子性" class="headerlink" title="volatile不保证原子性"></a>volatile不保证原子性</h4><blockquote>
<p>比如: i++</p>
</blockquote>
<p>如果是多线程环境下，一个线程读取到i的值到工作内存，然后对i做出自增操作，<br>然后写回主内存，其它内存才知道i的值被修改了，这个过程本身就不是原子的。<br>所以不能拿volatile来带替synchronized,如果是多线程环境，仍然需要使用synchronized保证线程同步。</p>
<h3 id="CAS"><a href="#CAS" class="headerlink" title="CAS"></a>CAS</h3><p>CAS: Compare And Swap 比较成功并交换。<br>CAS体现的是一种乐观锁的机制。<br><strong>CAS涉及到3个元素: 指定的内存地址,期盼值和目标值。</strong><br>它将指定内存地址的值与期盼值相比较，如果比较成功就将内存地址的值修改为目标值。</p>
<h4 id="CAS在JAVA中的底层实现-Atomic原子类实现"><a href="#CAS在JAVA中的底层实现-Atomic原子类实现" class="headerlink" title="CAS在JAVA中的底层实现(Atomic原子类实现)"></a>CAS在JAVA中的底层实现(Atomic原子类实现)</h4><p>CAS在Java中的实现是 juc的atomic包下的Atomicxx原子类。</p>
<p>而这些Atomic原子类的核心是: <unsafe>类<br>Unsafe类是个final类，它的核心方法都是native的，<br>因为Java无法像C/C++一样使用指针来操作内存,<br>Unsafe类就解决了这个问题。</unsafe></p>
<blockquote>
<p>拿incrementAndGet方法来说，<br>Unsafe首先调用getAndAddInt方法,<br>它会根据当前Atomic的value在内存中地址获取到当前对象的值,<br>然后再重复一遍此操作，把之前获得的值与第二遍获得的值进行比较，<br>如果成功，就把内存地址的值更新为新值，否则就do while循环.</p>
</blockquote>
<p><strong>并且有个重要的细节就是,Atomic原子类内部的value值都是由volatile修饰的,<br>这就使得Atomic的值是对其他线程可见的。</strong></p>
<h4 id="CAS的缺点"><a href="#CAS的缺点" class="headerlink" title="CAS的缺点"></a>CAS的缺点</h4><ul>
<li><p>循环时间开销大: 我在看源码的时候，发现Atomic的CAS操作并没有进行CAS失败的退出处理，<br>只是单纯的循环比较并交换，这就让我很担心它的性能问题，<br>如果长时间不成功，那会是很可怕的一件事请，至少cpu的负荷会很大。</p>
</li>
<li><p>只能保证一个共享变量的原子操作: Atomic原子类只能保证一个变量的原子操作，<br>如果是多数据的话，还是考虑用互斥锁来实现数据的同步吧</p>
</li>
<li><p>ABA问题: ABA问题是指如果一个线程进行CAS操作并成功了，却不代表这个过程就是没有问题的。</p>
</li>
</ul>
<blockquote>
<blockquote>
<p>假设2个线程读取了同一份数据，线程1修改了这个值并把它改回了原值，并同步到主内存中，<br>另一个线程准备进行CAS操作,当它发现原值和期盼的值是一样的，那么CAS仍然成功。</p>
</blockquote>
</blockquote>
<h4 id="解决ABA问题"><a href="#解决ABA问题" class="headerlink" title="解决ABA问题"></a>解决ABA问题</h4><p>在juc的atomic包中提供了 AtomicStampedReference 类,<br>这个类较普通的原子类新增了一个stamp字段，它的作用相当于version。<br>每次修改这个引用的值，也都会修改stamp的值，<br>当发现stamp的值与期盼的stamp不一样，也会修改失败.<br>这就类似于以version实现乐观锁一样。             </p>
<h4 id="ThreadLocal"><a href="#ThreadLocal" class="headerlink" title="ThreadLocal"></a>ThreadLocal</h4><p>ThreadLocal为每个线程都提供了一份相同的变量的副本，<br>每个线程都可以修改这个副本，但不用担心与其他线程发生数据冲突，<br>实现了线程之间的数据隔离。</p>
<p>ThreadLocal的原理还得从Thread线程类说起，<br><strong>每个Thread类内部都有一个ThreadLocalMap，当使用ThreadLocal的get和remove操作的时候，<br>就是使用每个线程的ThreadLocalMap的get和remove。</strong></p>
<h4 id="ThreadLocal引发的内存泄露"><a href="#ThreadLocal引发的内存泄露" class="headerlink" title="ThreadLocal引发的内存泄露"></a>ThreadLocal引发的内存泄露</h4><p><strong>在ThreadLocalMap中，key是使用弱引用的ThreadLocal存储的。</strong><br>弱引用是只要垃圾回收器开始回收，无论内存是否充足，都会回收掉弱引用对象，如此一来，<br>当ThreadLocal被回收掉,那么ThreadLocalMap将可能出现Null Key 的 value。但是也不必太过担心，<br>因为设计者已经想到了这点，所以ThreadLocal会自动处理key 为 null的 value。</p>
<h4 id="线程池的好处"><a href="#线程池的好处" class="headerlink" title="线程池的好处"></a>线程池的好处</h4><blockquote>
<p>http连接池，数据库连接池，线程池等都是利用了池化技术。<br>如果一个资源需要多次使用并且很昂贵，那么使用new创建的对象或资源，可能会带来较大的消耗。</p>
</blockquote>
<p>池化技术的好处在于</p>
<ol>
<li>方便资源的管理，无需显示的使用new创建。</li>
<li>降低了资源的消耗，在池子里的资源可以重复利用</li>
<li>提供了任务的响应速度，任务可以很快的被分配资源进行处理。</li>
</ol>
<h4 id="线程池构造参数"><a href="#线程池构造参数" class="headerlink" title="线程池构造参数"></a>线程池构造参数</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"> new ThreadPoolExecutor</span><br><span class="line">(int corePoolSize,</span><br><span class="line"></span><br><span class="line"> int maximumPoolSize, </span><br><span class="line"></span><br><span class="line"> long keepAliveTime,</span><br><span class="line"></span><br><span class="line"> TimeUnit unit,</span><br><span class="line"></span><br><span class="line"> BlockingQueue&lt;Runnable&gt; workQueue,</span><br><span class="line"></span><br><span class="line"> ThreadFactory threadFactory,</span><br><span class="line"></span><br><span class="line"> RejectedExecutionHandler handler)</span><br></pre></td></tr></table></figure>
<ol>
<li><p>corePoolSize: 线程池的核心线程数(常驻线程数),也就是线程池的最小线程数,这部分线程不会被回收.</p>
</li>
<li><p>maximumPoolSize: 线程池最大线程数,线程池中允许同时执行的最大线程数量</p>
</li>
<li><p>keepAliveTime: 当线程池中的线程数量超过corePoolSize，但此时没有任务执行，<br>那么空闲的线程会保持keepAliveTime才会被回收，corePoolSize的线程不会被回收。</p>
</li>
<li><p>unit: KeepAliveTime的时间单位</p>
</li>
<li><p>workQueue: 当线程池中的线程达到了corePoolSize的线程数量，<br>并仍然有新任务，那么新任务就会被放入workQueue。          </p>
</li>
<li><p>threadFactory: 创建工作线程的工厂,也就是如何创建线程的,一般采用默认的</p>
</li>
<li><p>handler: 拒绝策略，当线程池中的工作线程达到了最大数量，<br>并且阻塞队列也已经满了，那么拒绝策略会决定如何处理新的任务。ThreadPoolExecutor 提供了四种策略:</p>
<ul>
<li><p>AbortPolicy(是线程池的默认拒绝策略): 如果使用此拒绝策略，那么将对新的任务抛出RejectedExecutionException异常，来拒绝任务。</p>
</li>
<li><p>DiscardPolicy: 如果使用此策略，那么会拒绝执行新的任务，但不会抛出异常。</p>
</li>
<li><p>DiscardOldestPolicy: 如果使用此策略，那么不会拒绝新的任务，但会抛弃阻塞队列中等待最久的那个线程。     </p>
</li>
<li><p>CallerRunsPolicy: 如果使用此策略，不会拒绝新的任务，但会让调用者执行线程。<br>也就是说哪个线程发出的任务，哪个线程执行。</p>
</li>
</ul>
</li>
</ol>
<h4 id="阿里巴巴开发者手册不建议开发者使用Executors创建线程池"><a href="#阿里巴巴开发者手册不建议开发者使用Executors创建线程池" class="headerlink" title="阿里巴巴开发者手册不建议开发者使用Executors创建线程池"></a>阿里巴巴开发者手册不建议开发者使用Executors创建线程池</h4><p><strong>newFixedThreadPool和newSingleThreadPoolExecutor都是创建固定线程的线程池,<br>尽管它们的线程数是固定的，但是它们的阻塞队列的长度却是Integer.MAX_VALUE的,所以，<br>队列的任务很可能过多，导致OOM。</strong></p>
<p><strong>newCacheThreadPool和newScheduledThreadPool创建出来的线程池的线程数量却是Integer.MAX_VALUE的，<br>如果任务数量过多,也很可能发生OOM。</strong></p>
<h3 id="AQS-AbstractQueuedSynchronizer"><a href="#AQS-AbstractQueuedSynchronizer" class="headerlink" title="AQS(AbstractQueuedSynchronizer)"></a>AQS(AbstractQueuedSynchronizer)</h3><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">AQS是Doug Lea大师为JDK编写的一套基于API层面的抽象队列同步器.</span><br><span class="line">AbstractQueuedSynchronizer,抽象队列同步器.</span><br><span class="line">Lock,CountDownLatch等等这些并发工具都是基于AQS来实现的。</span><br><span class="line">由此可以看出Doug Lea大师的功力已经臻至化境</span><br></pre></td></tr></table></figure>
<h4 id="AQS概述"><a href="#AQS概述" class="headerlink" title="AQS概述"></a>AQS概述</h4><p><strong>AQS的核心思想是如果被请求的资源空闲，那么就将当前请求资源的线程设置为有效的工作线程;<br>如果请求的资源被其他线程所占有， 那么就使用CLH线程阻塞队列来提供阻塞线程并唤线程分配资源的机制。<br>在CLH队列中，每个请求资源的线程都会被封装成队列中的一个节点。</strong></p>
<p><strong>在AQS内部有一个int类型的state表示线程同步状态，<br>当线程lock获取到锁后，该state计数就加1,unlock就减1，<br>这就是为什么解锁次数要对应加锁次数的原因。</strong></p>
<p><strong>AQS主要实现技术为:CLH队列(Craig,Landin and Hagersten)，<br>自旋CAS，park(阻塞线程)以及unparkSuccessor(唤醒阻塞队列中的后继线程)。</strong></p>
<h4 id="AQS的两种共享资源的访问方式"><a href="#AQS的两种共享资源的访问方式" class="headerlink" title="AQS的两种共享资源的访问方式"></a>AQS的两种共享资源的访问方式</h4><blockquote>
<p>AQS定义了两种共享资源方式.</p>
</blockquote>
<ol>
<li>独占式(Exclusive): <strong>同一时间只有一个线程可以访问共享资源,也就是独占锁。</strong><br>如:Synchronized,ReentrantLock。<br><strong>对于独占式锁的实现,在AQS中对应tryAcquire获取锁和tryRelease释放锁。</strong></li>
</ol>
<ul>
<li>共享式(Share): <strong>同一时间允许多个线程同时访问共享资源,也就是共享锁。</strong><br>CountDownLatch,Semaphore,ReentrantReadWriteLock的ReadLock都是共享锁。<br><strong>对于共享式锁的实现,在AQS中对应tryAcquireShare获取锁和tryReleaseShare释放锁。</strong></li>
</ul>
<h4 id="lock-tryLock和lockInterruptibly区别"><a href="#lock-tryLock和lockInterruptibly区别" class="headerlink" title="lock,tryLock和lockInterruptibly区别"></a>lock,tryLock和lockInterruptibly区别</h4><p><strong>PS: AQS中的锁计数指的是 state 变量。</strong></p>
<ul>
<li><p>lock: 如果线程获取到了锁或线程已经拥有了锁就更改锁计数，<br>否则线程就加入阻塞队列并一直CAS自旋获取。</p>
</li>
<li><p>tryLock: 线程尝试获取锁，如果线程获取到了锁或线程已经拥有了锁就更改锁计数，否则返回false。</p>
</li>
<li><p>lockInterruptibly: 如果线程在获取锁之前被设置了中断状态，那么当线程获取锁时就会响应中断状态，<br>抛出InterruptedException异常。如果获取不到就加入阻塞队列并自旋获取，并且阻塞自旋期间还会响应中断，<br>也就是说在阻塞自旋期间可能抛出InterruptedException异常。<br><strong>所以lockInterruptibly优先响应中断，而不是优先获取锁。</strong><br>如果线程获取到了锁或线程已经拥有了锁才更改锁计数。</p>
</li>
</ul>
<h4 id="CountDownLatch"><a href="#CountDownLatch" class="headerlink" title="CountDownLatch"></a>CountDownLatch</h4><blockquote>
<p>CountDownLatch允许count个线程阻塞在一个地方，直至所有线程的任务都执行完毕。</p>
</blockquote>
<p>CountDownLatch是共享锁的一种实现,<strong>它默认构造AQS的state为count。<br>当线程使用countDown方法时,其实使用了tryReleaseShared方法以CAS的操作来减少state,<br>直至state为0就代表所有的线程都调用了countDown方法。</strong><br>假如某线程A调用await方法时，如果state不为0，就代表还有线程未执行countDown方法，<br>那么就把线程A放入阻塞队列Park，并自旋CAS判断state == 0。<br>直至最后一个线程调用了countDown，使得state == 0，<br>于是阻塞的线程判断成功，并被唤醒，就继续往下执行。</p>
<h4 id="Semaphore"><a href="#Semaphore" class="headerlink" title="Semaphore"></a>Semaphore</h4><blockquote>
<p>Semaphore允许一次性最多(不是同时)permits个线程执行任务。</p>
</blockquote>
<p>Semaphore与CountDownLatch一样，也是共享锁的一种实现。<br><strong>它默认构造AQS的state为permits。<br>当执行任务的线程数量超出permits,那么多余的线程将会被放入阻塞队列Park,并自旋判断state是否大于0。<br>只有当state大于0的时候，阻塞的线程才有机会继续执行,此时先前执行任务的线程继续执行release方法，<br>release方法使得state的变量会加1，那么自旋的线程便会判断成功。</strong></p>
<p>如此，<strong>每次只有不超过permits个的线程能自旋成功，便限制了执行任务线程的数量。</strong><br>所以这也是我为什么说它可能不是permits个线程同时执行，<br>因为只要state&gt;0,线程就有机会执行.</p>
<h4 id="CycliBarrier"><a href="#CycliBarrier" class="headerlink" title="CycliBarrier"></a>CycliBarrier</h4><p>CycliBarrier的功能与CountDownLatch相似，但是<strong>CountDownLatch的实现是基于AQS的，<br>而CycliBarrier是基于ReentrantLock(ReentrantLock也属于AQS同步器)和Condition的。</strong></p>
<p>CountDownLatch虽然可以令多个线程阻塞在同一代码处，但只能await一次就不能使用了。<br>而CycliBarrier有Generation代的概念，一个代，就代表CycliBarrier的一个循环，<br>这也是CycliBarrier支持重复await的原因。 </p>
<h4 id="ReentrantReadWriteLock如何区分读写锁的"><a href="#ReentrantReadWriteLock如何区分读写锁的" class="headerlink" title="ReentrantReadWriteLock如何区分读写锁的?"></a>ReentrantReadWriteLock如何区分读写锁的?</h4><p><strong>Sync既有写锁，又有读锁，因此一个state不够用，<br>所以使用state的高16为表示读锁，低位16表示写锁.</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">ReentrantReadWriteLock部分源码:</span><br><span class="line"></span><br><span class="line">static final int SHARED_SHIFT   = 16;</span><br><span class="line">static final int SHARED_UNIT    = (1 &lt;&lt; SHARED_SHIFT);</span><br><span class="line">static final int MAX_COUNT      = (1 &lt;&lt; SHARED_SHIFT) - 1;</span><br><span class="line">static final int EXCLUSIVE_MASK = (1 &lt;&lt; SHARED_SHIFT) - 1;</span><br><span class="line"></span><br><span class="line">/** Returns the number of shared holds represented in count. */</span><br><span class="line">static int sharedCount(int c)    &#123; return c &gt;&gt;&gt; SHARED_SHIFT; &#125;</span><br><span class="line">/** Returns the number of exclusive holds represented in count. */</span><br><span class="line">static int exclusiveCount(int c) &#123; return c &amp; EXCLUSIVE_MASK; &#125;</span><br></pre></td></tr></table></figure>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">剩下的就读源码吧。</span><br></pre></td></tr></table></figure>
<p>其实吧，在我读了几遍源码后,才发现jdk的源码不算特别不难阅读。</p>
<p>但是像我在读SpringBoot的源码时，我就只能分析个大概。</p>
<p>主要是Jdk的源码之间并没有什么耦合性，你看一个jdk的类，不像Spring的源码那样绕来绕去，<br>各种设计模式搞得你头晕。<br>所以我建议阅读源码可以从jdk的源码开始，前提是你需要一定的基础才能看得懂。<br>比如我这个版本(11)就发现AQS的部分源码与之前版本的源码不同。<br>这个版本的AQS使用了: VarHandle 这个类来设置Node类内部的属性，<br>而之前都是直接使用构造方法来构造Node的。<br>并且AQS使用的是LockSupport来阻塞线程的，LockSupport仍然使用的是Unsafe类来进行操作的,<br>这些都属于java与c/c++交互的类,所以你如果没有基础，会诧异,jdk还有这种东西呀 ^-^…            </p>
<hr>
<h2 id="Java集合"><a href="#Java集合" class="headerlink" title="Java集合"></a>Java集合</h2><h4 id="HashMap的特点"><a href="#HashMap的特点" class="headerlink" title="HashMap的特点"></a>HashMap的特点</h4><ul>
<li><p>HashMap在Jdk8之前使用拉链法实现,jdk8之后使用拉链法+红黑树实现。</p>
</li>
<li><p>HashMap是线程不安全的,并允许null key 和 null value。**</p>
</li>
<li><p>HashMap在我当前的jdk版本(11)的默认容量为0,在第一次添加元素的时候才初始化容量为 16,<br>之后才扩容为原来的2倍。</p>
</li>
<li><p>HashMap的扩容是根据 threshold决定的 : threshold = loadfactory * capacity。<br>当 size 大于 threshold 时,扩容。</p>
</li>
<li><p><strong>当每个桶的元素数量达到默认的阈值TREEIFY_THRESHOLD(8)时,那么这个桶的链表将会转为红黑树。<br>当红黑树节点的数量低于默认的阈值UNTREEIFY_THRSHOLD(6)时，那么这个桶的红黑树将转为链表</strong></p>
</li>
</ul>
<h4 id="HashMap的长度-容量-为什么要设计成2的幂？"><a href="#HashMap的长度-容量-为什么要设计成2的幂？" class="headerlink" title="HashMap的长度(容量)为什么要设计成2的幂？"></a>HashMap的长度(容量)为什么要设计成2的幂？</h4><blockquote>
<p>这就不得不佩服大师们的设计。</p>
</blockquote>
<p>想想看，一个对象的hashcode是很大的，当HashMap的容量仅为16,32时，<br>如何根据hashcode来确定key在数组中的下标。<br>一个好的办法就是取余: hashcode % length。<br>这样就能确保，key的下标是永远不会超过数组的长度的。<br>但是想想，除了取余有没有更好的办法，</p>
<p>当然有:<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">hash % length == hash &amp; (length - 1)</span><br></pre></td></tr></table></figure></p>
<p>为什么上面这个性能超高的等式成立，当然是有条件的，</p>
<p><strong>只有当length为2的幂的时候这样的等式才成立,</strong><br>这就明白了为什么使用2的幂来定义HashMap的长度。</p>
<h4 id="HashTable的特点"><a href="#HashTable的特点" class="headerlink" title="HashTable的特点"></a>HashTable的特点</h4><ul>
<li><p>HashTable底层使用拉链法实现。</p>
</li>
<li><p>HashTable就像Vector一样,也是jdk1就存在的很古老的一个类，它是线程安全的，<br>实现线程安全的手段是使用synchronized。</p>
</li>
<li><p>HashTable的默认容量为16，每次扩容为原来的2倍+1。</p>
</li>
<li><p>HashTable不允许null key 和 null value。</p>
</li>
</ul>
<h4 id="TreeMap"><a href="#TreeMap" class="headerlink" title="TreeMap"></a>TreeMap</h4><p><strong>TreeMap使用红黑树实现,不允许null key,允许自然排序Comparable和比较器Comparator排序。</strong></p>
<h4 id="ArrayList的特点"><a href="#ArrayList的特点" class="headerlink" title="ArrayList的特点"></a>ArrayList的特点</h4><ul>
<li><p>ArrayList底层使用Object数组实现。</p>
</li>
<li><p>ArrayList的容量默认为0,只有在第一次执行add操作时才会初始化容量为10。</p>
</li>
<li><p>由于ArrayList采用数组实现,它的容量是固定的,所以当添加新元素的时候,如果超出了数组的容量,<br>那么此时add操作的时间复杂度将会是O(n-1)。</p>
</li>
<li><p>ArrayList实现了RandomAccess接口，该接口没有具体的规范，只是一个标记，<br>这代表ArrayList支持快速的随机访问。</p>
</li>
<li><p>ArrayList在内存空间利用率上肯定是不如LinkedList的，<br>因为数组是一片固定的连续的内存空间，一旦分配就无法改变，<br>所以难免会有空间不足或空间使用率很低的情况。</p>
</li>
</ul>
<h4 id="Vector的特点"><a href="#Vector的特点" class="headerlink" title="Vector的特点"></a>Vector的特点</h4><ol>
<li><p>ArrayList是线程不安全的，Vector是线程安全的，<br>但Vector实现线程安全的手段是synchronized。这就好比HashMap与HashTable的区别。</p>
</li>
<li><p>Vector默认容量为10。</p>
</li>
<li><p>Vector是当它的扩容增量大于0时，会扩容为原来的容量+扩容增量，否则扩容为原来的2倍。</p>
</li>
</ol>
<h4 id="LinkedList的特点"><a href="#LinkedList的特点" class="headerlink" title="LinkedList的特点"></a>LinkedList的特点</h4><ul>
<li><p>LinkedList底层使用双向链表实现。</p>
</li>
<li><p>LinkedList的add操作只需要改变尾节点的引用就行了。<br>但是如果需要在指定位置进行add操作的话，那么时间复杂度也是比较高的,为O(n)，<br>因为需要从头节点或尾节点遍历到需要操作的节点。</p>
</li>
<li><p>LinkedList的空间利用率虽然很高，但是它的每个Node可以说也是占用了较大空间的，<br>因为每个Node需要保存它的前继和后继节点。</p>
</li>
</ul>
<p><strong>ps: 双向链表与双向循环链表的区别:<br>双向链表:每个Node都保存了前后2个节点的引用，双向链表的first节点的前一个节点为null,<br> last节点的后一个节点为null。</strong></p>
<p><strong>双向循环链表: 每个Node都保存了前后2个节点的引用，<br>双向循环链表的first节点的前一个节点指向last节点，<br>last节点的最后一个节点指向first节点。</strong></p>
<h4 id="Set"><a href="#Set" class="headerlink" title="Set"></a>Set</h4><p>为啥不单独说HashSet，我目前看到的JDK所有的Set,都是使用Map实现的,<br>除了CopyOnWriteArraySet(底层是CopyOnWriteArrayList)。</p>
<p>TreeSet –&gt; TreeMap</p>
<p>LinkedHashSet –&gt; LinkedHashMap</p>
<p>HashSet –&gt; HashMap</p>
<p>ConcurrentSkipListSet –&gt; ConcurrentSkipListMap</p>
<p>Set是如何保证元素不会重复,这个得看各自Map的实现了。</p>
<p>拿HashMap来讲，它就是先判断key的hashcode是否相等，然后才使用equals判断2个对象是否相等。</p>
<h4 id="ConcurrentModificationException异常"><a href="#ConcurrentModificationException异常" class="headerlink" title="ConcurrentModificationException异常"></a>ConcurrentModificationException异常</h4><p>ConcurrentModificationException可以从名字看出是并发修改的异常。</p>
<p>但我要说的是<strong>这个异并不是在修改的时候会抛出的，而是在调用迭代器遍历集合的时候才会抛出。</strong></p>
<p>而集合类的大部分toString方法，都是使用迭代器遍历的。<strong>所以如果多线程修改集合后，<br>接着就遍历集合，那么很有可能会抛出ConcurrentModificationException。</strong></p>
<p><strong>在ArrayList，HashMap等非线程安全的集合内部都有一个modCount变量，<br>这个变量是在集合被修改时(删除，新增)，都会被修改。</strong></p>
<p>如果是多线程对同一个集合做出修改操作，就可能会造成modCount与实际的操作次数不符，<br>那么最终在调用集合的迭代方法时，modCount与预期expectedModeCount比较，<br>expectedModCount是在迭代器初始化时使用modCount赋值的，<br><strong>如果发现modCount与expectedModeCount不一致，就说明在使用迭代器遍历集合期间，<br>有其他线程对集合进行了修改,所以就会抛出ConcurrentModificationException异常。</strong></p>
<h4 id="线程安全的-List"><a href="#线程安全的-List" class="headerlink" title="线程安全的 List"></a>线程安全的 List</h4><ol>
<li>使用集合工具类Collections的 synchronizedList把普通的List转为线程安全的List.(不推荐)</li>
<li>使用Vector.(不推荐)</li>
<li>使用CopyOnWriteArrayList,推荐使用此种方法，因为以上2种全部都是单纯的Synchronized加锁.</li>
</ol>
<h4 id="CopyOnWriteArrayList"><a href="#CopyOnWriteArrayList" class="headerlink" title="CopyOnWriteArrayList"></a>CopyOnWriteArrayList</h4><p>CopyOnWriteArrayList是线程安全的ArrayList，可以被称为写时复制的ArrayList。<br>CopyOnWriteArrayList底层仍然使用数组实现，<br>但是它的修改操作(增删改)采用synchronized关键字保证并发的安全性，<br>然后<strong>在进行修改的时候复制原来的数组到一个新副本，对新副本进行修改，修改完后再设置原数组。</strong><br>这样就不会让写操作影响读操作了。 </p>
<p><strong>但是CopyOnWriteArrayList不容忽视的缺点就是修改操作比较消耗内存空间，所以它适用于读多写少的环境。</strong></p>
<h4 id="线程安全的Set"><a href="#线程安全的Set" class="headerlink" title="线程安全的Set"></a>线程安全的Set</h4><ol>
<li>使用集合工具类的Collections的synchronizedSet把普通的set转为线程安全的set(不推荐)</li>
<li>使用CopyOnWriteArraySet,此set适用于读多写少的情况，它的底层采用CopyOnWriteArrayList实现.</li>
<li>使用ConcurrentSkipListSet，底层采用ConcurrentSkipListMap实现</li>
</ol>
<h4 id="线程安全的Map"><a href="#线程安全的Map" class="headerlink" title="线程安全的Map"></a>线程安全的Map</h4><ol>
<li>使用集合工具类Collections的synchronizedMap把普通map转为线程安全的map(不推荐)</li>
<li>HashTable(不推荐)</li>
<li>使用ConcurrentHashMap(常用)</li>
<li>ConcurrentSkipListMap(跳表map,推荐)</li>
</ol>
<h4 id="ConcurrentHashMap"><a href="#ConcurrentHashMap" class="headerlink" title="ConcurrentHashMap"></a>ConcurrentHashMap</h4><p>ConcurrentHashMap使用数组+链表/红黑树实现,其扩容机制与HashMap一样。</p>
<p><strong>但是ConcurrentHashMap控制并发的方法改为了CAS+synchronized,<br>synchronized锁的只是链表的首节点或红黑树的首节点。</strong></p>
<p><strong>PS:我只看了常用的put,get,remove等核心方法的源码.<br>整个ConcurrentHashMap的实现用”复杂”来形容一点也不为过,<br>你只要想到它内部有52个内部类就知道有多复杂了,但如果不考虑并发CAS这部分，<br>ConcurrentHashMap和普通的HashMap的差别是不大的。</strong></p>
<h4 id="ConcurrentSkipListMap"><a href="#ConcurrentSkipListMap" class="headerlink" title="ConcurrentSkipListMap"></a>ConcurrentSkipListMap</h4><p>ConcurrentSkipListMap是基于跳表这种数据结构实现的。<br>跳表比较特殊，它由多个层次的链表组成，每层链表又有多个索引节点连接，<br>每层链表的元素也都是有序的。处于上层索引的链表都是下层链表的子集。<br>跳表与普通链表相比查找元素的效率更高。</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/跳表.png" alt="跳表" title="">
                </div>
                <div class="image-caption">跳表</div>
            </figure>
<hr>
<h2 id="Java-IO"><a href="#Java-IO" class="headerlink" title="Java IO"></a>Java IO</h2><h3 id="操作系统的内核"><a href="#操作系统的内核" class="headerlink" title="操作系统的内核"></a>操作系统的内核</h3><p>操作系统的内核是操作系统的核心部分。<br>它负责系统的内存管理，硬件设备的管理，文件系统的管理以及应用程序的管理。</p>
<p><strong>IO图源:<br><a href="https://www.jianshu.com/p/85e931636f27" target="_blank" rel="noopener">简书</a> (如有侵权,请联系俺,俺会立刻删除)</strong></p>
<h4 id="操作系统的用户态与内核态"><a href="#操作系统的用户态与内核态" class="headerlink" title="操作系统的用户态与内核态"></a>操作系统的用户态与内核态</h4><p>unix与linux的体系架构：分为用户态与内核态。<br>用户态与内核态与内核态是操作系统对执行权限进行分级后的不同的运行模式。</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/用户态与内核态.png" alt="用户态与内核态" title="">
                </div>
                <div class="image-caption">用户态与内核态</div>
            </figure>
<h4 id="为什么要有用户态与内核态"><a href="#为什么要有用户态与内核态" class="headerlink" title="为什么要有用户态与内核态?"></a>为什么要有用户态与内核态?</h4><p>在cpu的所有指令中，有些指令是非常危险的，如果使用不当，将会造成系统崩溃等后果。<br>为了避免这种情况发生，cpu将指令划分为<strong>特权级(内核态)指令</strong>和<strong>非特权级(用户态)指令。</strong></p>
<p><strong>对于那些危险的指令只允许内核及其相关模块调用，对于那些不会造成危险的指令，就允许用户应用程序调用。</strong></p>
<ul>
<li><p>内核态(核心态,特权态): <strong>内核态是操作系统内核运行的模式。</strong><br>内核态控制计算机的硬件资源，如硬件设备，文件系统等等，并为上层应用程序提供执行环境。</p>
</li>
<li><p>用户态: <strong>用户态是用户应用程序运行的状态。</strong><br>应用程序必须依托于内核态运行,因此用户态的态的操作权限比内核态是要低的，<br>如磁盘，文件等，访问操作都是受限的。</p>
</li>
<li><p>系统调用: 系统调用是操作系统为应用程序提供能够访问到内核态的资源的接口。</p>
</li>
</ul>
<h4 id="用户态切换到内核态的几种方式"><a href="#用户态切换到内核态的几种方式" class="headerlink" title="用户态切换到内核态的几种方式"></a>用户态切换到内核态的几种方式</h4><ul>
<li><p>系统调用: 系统调用是用户态主动要求切换到内核态的一种方式，<br>用户应用程序通过操作系统调用内核为上层应用程序开放的接口来执行程序。</p>
</li>
<li><p>异常: 当cpu在执行用户态的应用程序时，发生了某些不可知的异常。<br>于是当前用户态的应用进程切换到处理此异常的内核的程序中去。</p>
</li>
<li><p>硬件设备的中断: 当硬件设备完成用户请求后，会向cpu发出相应的中断信号，<br>这时cpu会暂停执行下一条即将要执行的指令，转而去执行与中断信号对应的应用程序，<br>如果先前执行的指令是用户态下程序的指令，那么这个转换过程也是用户态到内核台的转换。</p>
</li>
</ul>
<h4 id="阻塞和非阻塞"><a href="#阻塞和非阻塞" class="headerlink" title="阻塞和非阻塞"></a>阻塞和非阻塞</h4><ol>
<li><p>阻塞: 一个线程调用一个方法计算 1 - 100 的和，如果该方法没有返回，<br>那么调用的线程就一直等待该方法返回，不继续往下执行。</p>
</li>
<li><p>非阻塞: 一个线程调用一个方法计算 1 - 100的和，如果该方法没有返回，<br>调用者线程也无需一直等待该方法返回，可以执行其他任务，但是线程仍然需要不断检查方法是否返回。</p>
</li>
</ol>
<p><strong>结论: 阻塞与非阻塞针对调用者的立场而言。</strong></p>
<h4 id="同步与异步"><a href="#同步与异步" class="headerlink" title="同步与异步"></a>同步与异步</h4><ol>
<li>同步: 一个线程调用一个方法计算 1 - 100 的和，如果方法没有计算完，就不返回。</li>
<li>异步: 一个线程调用一个方法计算 1 - 100 的和，该方法立刻返回，但是由于方法没有返回结果，<br>所以就需要被调用的这个方法来通知调用线程 1 - 100的结果，<br>或者线程在调用方法的时候指定一个回调函数来告诉被调用的方法执行完后就执行回调函数。</li>
</ol>
<p><strong>结论:同步和异步是针对被调用者的立场而言的。</strong></p>
<h3 id="Linux-IO模型"><a href="#Linux-IO模型" class="headerlink" title="Linux IO模型"></a>Linux IO模型</h3><p>Linux下共有5种IO模型:</p>
<ol>
<li>阻塞IO</li>
<li>非阻塞IO</li>
<li>多路复用IO</li>
<li>信号驱动IO</li>
<li>异步IO</li>
</ol>
<h4 id="阻塞IO"><a href="#阻塞IO" class="headerlink" title="阻塞IO"></a>阻塞IO</h4><p>阻塞IO是很常见的一种IO模型。<br>在这种模型中，<strong>用户态的应用程序会执行一个操作系统的调用，<br>检查内核的数据是否准备好。如果内核的数据已经准备好，<br>就把数据复制到用户应用进程。如果内核没有准备好数据，<br>那么用户应用进程(线程)就阻塞，直到内核准备好数据并把数据从<br>内核复制到用户应用进程，</strong> 最后应用程序再处理数据。</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/BIO原理.png" alt="BIO原理" title="">
                </div>
                <div class="image-caption">BIO原理</div>
            </figure>
<p><strong>阻塞IO是同步阻塞的。</strong></p>
<ol>
<li><p>阻塞IO的同步体现在: <strong>内核只有准备好数据并把数据复制到用户应用进程才会返回。</strong></p>
</li>
<li><p>阻塞IO的阻塞体现在:<strong>用户应用进程等待内核准备数据和把数据从用户态拷贝到内核态的这2段时间。</strong><br>当然,如果是本地磁盘IO,内核准备数据的时间可能会很短。<br>但网络IO就不一样了，因为服务端不知道客户端何时发送数据，<br>内核就仍需要等待socket数据，时间就可能会很长。</p>
</li>
</ol>
<blockquote>
<p><strong>阻塞IO的优点是对于数据是能够保证无延时的，因为应用程序进程会一直阻塞直到IO完成。</strong><br>但应用程序的阻塞就意味着应用程序进程无法执行其他任务，<br>这会大大降低程序性能。一个不太可行的办法是为每个客户端socket都分配一个线程，<br>这样就会提升server处理请求的能力。不过操作系统的线程资源是有限的，<br>如果请求过多，可能造成线程资源耗尽，系统卡死等后果。</p>
</blockquote>
<h4 id="非阻塞IO-网络IO模型"><a href="#非阻塞IO-网络IO模型" class="headerlink" title="非阻塞IO(网络IO模型)"></a>非阻塞IO(网络IO模型)</h4><p>在非阻塞IO模型中，用户态的应用程序也会执行一个操作系统的调用，<br>检查内核的数据是否准备完成。<strong>如果内核没有准备好数据,<br>内核会立刻返回结果,用户应用进程不用一直阻塞等待内核准备数据，<br>而是可以执行其他任务,但仍需要不断的向内核发起系统调用，检测数据是否准备好，<br>这个过程就叫轮询。</strong> 轮询直到内核准备好数据，然后内核把数据拷贝到用户应用进程，<br>再进行数据处理。</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/NIO原理.png" alt="NIO原理" title="">
                </div>
                <div class="image-caption">NIO原理</div>
            </figure>
<p>非阻塞IO的非阻塞体现在: <strong>用户应用进程不用阻塞在对内核的系统调用上</strong></p>
<blockquote>
<p>非阻塞IO的优点在于用户应用进程在轮询阶段可以执行其它任务。<br>但这也是它的缺点，轮询就代表着用户应用进程不是时刻都会发起系统调用。<br><strong>可能数据准备好了，而用户应用进程可能等待其它任务执行完毕才会发起系统调用，<br>这就意味着数据可能会被延时获取。</strong></p>
</blockquote>
<h4 id="多路复用IO-网络IO模型"><a href="#多路复用IO-网络IO模型" class="headerlink" title="多路复用IO(网络IO模型)"></a>多路复用IO(网络IO模型)</h4><p>在多路复用IO模型中,<strong>用户应用进程会调用操作系统的select/poll/epoll函数,<br>它会使内核同步的轮询指定的socket，<br>(在NIO,socket就是注册到Selector上的SocketChannel,可以允许多个)<br>直至监听的socket有数据可读或可写，select/poll/epoll函数才会返回,<br>用户应用进程也会阻塞的等待select/poll/epoll函数返回。</strong><br>当select/poll/epoll函数返回后，即某个socket有事件发生了，用户应用进程就会<br>发起系统调用，处理事件，将socket数据复制到用户进程内，然后进行数据处理。</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/多路复用IO原理.png" alt="多路复用IO原理" title="">
                </div>
                <div class="image-caption">多路复用IO原理</div>
            </figure>
<p><strong>多路复用IO模型是同步阻塞的</strong></p>
<ol>
<li><p>多路复用IO模型的同步体现在: <strong>select函数只有监听到某个socket有事件才会返回。</strong></p>
</li>
<li><p>多路复用IO模型的阻塞体现在: <strong>用户应用进程会阻塞在对select函数上的调用上。</strong></p>
</li>
</ol>
<blockquote>
<p><strong>多路复用IO的优点在于内核可以处理多个socket，<br>相当于一个用户进程(线程)就可以处理多个socket连接。</strong><br>这样不仅降低了系统的开销，并且对于需要高并发的应用是非常有利的。<br>而非阻塞IO和阻塞IO的一个用户应用进程只能处理一个socket，<br>要想处理多socket，只能新开进程或线程，但这样很消耗系统资源。</p>
</blockquote>
<p><strong>PS:<br>在多路复用IO模型中, socket一般应该为非阻塞的，<br>这就是Java中NIO被称为非阻塞IO的原因。<br>但实际上NIO属于多路复用IO，它是同步阻塞的IO。<br>具体原因见 <a href="https://www.zhihu.com/question/37271342" target="_blank" rel="noopener">知乎讨论</a></strong></p>
<p><strong>PS:<br>select/poll/epoll函数是多路复用IO模型的基础，所以如果想<br>深入了解多路复用IO模型，就需要了解这3个函数以及它们的优缺点。</strong></p>
<h4 id="信号驱动IO-网络IO模型"><a href="#信号驱动IO-网络IO模型" class="headerlink" title="信号驱动IO(网络IO模型)"></a>信号驱动IO(网络IO模型)</h4><p>在信号驱动IO模型中，<strong>用户应用进程发起sigaction系统调用,内核收到并立即返回。<br>用户应用进程可以继续执行其他任务，不会阻塞。当内核准备好数据后向用户应用进程<br>发送SIGIO信号，应用进程收到信号后，发起系统调用，<br>将数据从内核拷贝到用户进程，</strong> 然后进行数据处理。</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/信号驱动IO原理.png" alt="信号驱动IO原理" title="">
                </div>
                <div class="image-caption">信号驱动IO原理</div>
            </figure>
<p>个人感觉在内核收到系统调用就立刻返回这一点很像异步IO的方式了，不过<br>与异步IO仍有很大差别。</p>
<h4 id="异步IO"><a href="#异步IO" class="headerlink" title="异步IO"></a>异步IO</h4><p>在异步IO模型中，<strong>用户进程发起aio_read系统调用，无论内核的数据是否准备好，<br>都会立即返回。用户应用进程不会阻塞,可以继续执行其他任务。当内核准备好数据,<br>会直接把数据复制到用户应用进程。最后内核会通知用户应用进程IO完成。</strong></p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/异步IO原理.png" alt="异步IO原理" title="">
                </div>
                <div class="image-caption">异步IO原理</div>
            </figure>
<p><strong>异步IO的异步体现在:内核不用等待数据准备好就立刻返回，<br>所以内核肯定需要在IO完成后通知用户应用进程。</strong></p>
<hr>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">弄清楚了阻塞与非阻塞，同步与异步和上面5种IO模型，相信再看</span><br><span class="line">Java中的IO模型，也只是换汤不换药。</span><br></pre></td></tr></table></figure>
<ul>
<li>BIO : 阻塞IO</li>
<li>NIO : 多路复用IO</li>
<li>AIO : 异步IO</li>
</ul>
<p>本来打算写Java中的IO模型的，发现上面几乎讲完了(剩API使用吧)，没啥要写的了，<br>所以暂时就这样吧。如果各位同学有好的建议，欢迎pr或issue。</p>
<p><strong>PS:<br>我此处写的IO模型大部分是借鉴于网上的资料，如有错误，请各位同学指出。</strong></p>
<hr>
<h2 id="JVM"><a href="#JVM" class="headerlink" title="JVM"></a>JVM</h2><p><strong>JVM部分参考了《深入理解Java虚拟机》(周志明)</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">个人认为《深入理解Java虚拟机》上的部分内容已经过时</span><br><span class="line">有些知识请各位同学明鉴</span><br></pre></td></tr></table></figure>
<h3 id="JVM运行时内存分区"><a href="#JVM运行时内存分区" class="headerlink" title="JVM运行时内存分区"></a>JVM运行时内存分区</h3><blockquote>
<p>以HotSpot为例:</p>
</blockquote>
<ul>
<li><p>JDK8之前: </p>
<ul>
<li><p>线程私有的部分有:程序计数器(PC寄存器),JAVA虚拟机栈,本地方法栈(native)。</p>
</li>
<li><p>线程共享部分有: GC堆,永久代(是方法区的一种实现)。</p>
</li>
</ul>
</li>
</ul>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/jdk8之前的JVM内存分区.png" alt="jdk8之前的jvm内存分区" title="">
                </div>
                <div class="image-caption">jdk8之前的jvm内存分区</div>
            </figure>
<ul>
<li><p>JDK8之后:</p>
<p>-线程私有的部分不变, 线程共享部分的永久代改为了元空间(MetaSpace)<br> (永久代和元空间都是方法区的实现),字符串常量池也移动到了heap空间</p>
</li>
</ul>
<p><img src="/img/jdk8之后的jvm内存分区.png" alt="jdk8之后的jvm内存分区">     </p>
<h4 id="程序计数器"><a href="#程序计数器" class="headerlink" title="程序计数器"></a>程序计数器</h4><p>程序计数器是一块较小的内存空间，<strong>它的作用是作为当前线程执行的字节码的行号计数器。<br>当字节码解释器工作时，通过改变行号计数器的值来选取下一条要执行的字节码指令。</strong><br>分支，循环，跳转，异常处理，线程恢复等功能都需要依赖程序计数器完成。</p>
<p><strong>程序计数器是属于线程私有的部分。<br>当cpu在多个线程之间切换执行时，需要记录下当前线程执行的字节码的位置，<br>以便下次切换回当前线程时，能够继续执行字节码指令，<br>所以每个线程都需要有自己的程序计数器。</strong></p>
<h4 id="程序计数器的特点"><a href="#程序计数器的特点" class="headerlink" title="程序计数器的特点"></a>程序计数器的特点</h4><ol>
<li>如果当前线程执行的是java方法，那么程序计数器记录的是字节码指令的地址。</li>
<li>如果当前线程执行的native方法，那么程序计数器记录的值为空(undefined)。</li>
<li>程序计数器这部分内存区域是JVM中唯一不会出现OOM错误的区域</li>
<li>程序计数器的生命周期与线程相同,即程序计数器随着线程创建而创建，<br>随着线程的销毁而销毁。</li>
</ol>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">使用 javap -c 反编译class文件后的代码如下,</span><br><span class="line">红框里的就是字节码的偏移地址:</span><br></pre></td></tr></table></figure>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/JVM程序计数器.png" alt="JVM程序计数器" title="">
                </div>
                <div class="image-caption">JVM程序计数器</div>
            </figure>
<h4 id="Java虚拟机栈"><a href="#Java虚拟机栈" class="headerlink" title="Java虚拟机栈"></a>Java虚拟机栈</h4><p>Java虚拟机栈与程序计数器一样，都是线程私有的部分，生命周期也跟线程一样。</p>
<p><strong>Java虚拟机栈描述的是Java方法运行时的内存模型，它由一个一个的栈帧组成。</strong></p>
<h4 id="栈帧"><a href="#栈帧" class="headerlink" title="栈帧"></a>栈帧</h4><p><strong>栈帧是用于支持Java方法运行时的数据结构。<br>栈帧包含了局部变量表，操作数栈，动态连接，方法出口等信息。<br>每个方法执行时，都会在java虚拟机栈中创建一个栈帧。<br>对方法的调用和返回，就对应着栈帧的入栈和出栈的过程。</strong></p>
<p>Java虚拟机栈:<br><figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/Java虚拟机栈.png" alt="Java虚拟机栈" title="">
                </div>
                <div class="image-caption">Java虚拟机栈</div>
            </figure></p>
<h4 id="局部变量表"><a href="#局部变量表" class="headerlink" title="局部变量表"></a>局部变量表</h4><p><strong>局部变量表用于存储方法参数和方法内定义的局部变量。<br>局部变量表存放了各种已知的数据类型的变量。</strong><br>一个局部变量的类型可以是基本数据类型<br>(int,short,float,double,boolean,long,byte,char)或引用类型(reference)。<br>在Java代码被编译成class字节码后，方法Code属性的locals就确定了方法的局部变量表的大小。<br>局部变量表以slot为最小单位，一个slot代表4个字节，也就是32位长度的大小。</p>
<h4 id="操作数栈"><a href="#操作数栈" class="headerlink" title="操作数栈"></a>操作数栈</h4><p>操作数栈是一个后进先出(LIFO)的数据结构。<br><strong>它存储的是方法在进行数据运算时的元素。</strong><br>和局部变量表一样，操作数栈的每个元素的类型也可以是基本数据类型和引用类型。<br>操作数栈的深度不会超过 Code属性的stack值。</p>
<p>使用javap -c 反编译class文件后可以得到的字节码指令如下:</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/局部变量表.png" alt="局部变量表" title="">
                </div>
                <div class="image-caption">局部变量表</div>
            </figure>
<h4 id="动态连接"><a href="#动态连接" class="headerlink" title="动态连接"></a>动态连接</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">了解动态连接首先需要了解符号引用和直接引用</span><br></pre></td></tr></table></figure>
<ul>
<li><p>符号引用: 符号引用存于Class文件常量池。分为类的全限定名，方法名和描述符，字段名和描述符。</p>
</li>
<li><p>直接引用: 指向目标的指针，可以简单理解为目标的内存地址(如指向类的字段的内存地址)。</p>
</li>
</ul>
<p>Class文件常量池如下(javap -c 反编译class文件后的字节码):</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/Class文件常量池.png" alt="Class文件常量池" title="">
                </div>
                <div class="image-caption">Class文件常量池</div>
            </figure>
<p><strong>在虚拟机栈中，每个栈帧都包含了一个该栈帧所属方法的符号引用，<br>持有这个符号引用的目的是为了支持方法调用过程中的动态连接。<br>这些符号引用有的一部分会在JVM类解析阶段就会转为直接引用，这部分转换成为静态解析。<br>还有一部分会在运行时转为直接引用，这部分称为动态连接。</strong></p>
<h4 id="方法出口"><a href="#方法出口" class="headerlink" title="方法出口"></a>方法出口</h4><p>当方法执行时，有2种方式可以退出该方法。</p>
<ol>
<li><p>正常退出: 当方法执行时，执行到return指令，该方法就会正常退出。<br>一般来说，方法正常退出时，调用线程的程序计数器的值可以作为方法返回的地址，<br>栈帧中可能会保存这个计数器的值。</p>
</li>
<li><p>异常退出: 在方法执行过程中遇到了异常，并且方法内部没有处理这个异常，就会导致方法退出。<br>方法异常退出时，返回地址需要通过异常处理器表来确定的，栈帧中不会保存这部分值。</p>
</li>
</ol>
<p><strong>无论何种退出方式，在方法退出后，都需要回到方法被调用的位置，程序才能继续执行。</strong></p>
<h4 id="本地方法栈"><a href="#本地方法栈" class="headerlink" title="本地方法栈"></a>本地方法栈</h4><p>本地方法栈与虚拟机栈的作用是相似的，<br>不过<strong>虚拟机栈是为执行Java方法提供服务的，<br>本地方法栈视为执行native方法提供服务的。</strong><br>在本地方法执行的时候，也会在本地方法栈中创建栈帧，<br>用于存放该本地方法的局部变量表，操作数栈，动态连接和方法返回地址等信息。</p>
<h4 id="堆"><a href="#堆" class="headerlink" title="堆"></a>堆</h4><p><strong>堆是JVM中内存占用最大的一块区域，它是所有线程共享的一块区域。<br>堆的作用是为对象分配内存并存储和回收它们。<br>堆是垃圾回收的主要区域，所以堆区也被成为GC堆。</strong></p>
<p>堆区可以划分为 <strong>新生代(Young Generation),老年代(Old Generation)</strong> 和<br>永久代(Permanent Generation),但永久代已被元空间代替,<br><strong>元空间存储的是类的元信息，几乎不可能发生GC。</strong></p>
<p>新生代再细分可以分为: <strong>Eden空间，From Survivor空间和To Survivor空间。</strong></p>
<p>缺省状态下新生代占堆区的 1/3,老年代占堆区的2/3，<br>eden空间占新生代的80%,2个Survivor空间栈新生代的20%,<br>FromSurvivor和ToSurvivor的空间占比为1:1。</p>
<p>(通过-XX:NewRatio参数可以调整新生代和老年代的空间占比)<br>(通过-XX:SurvivorRatio参数可以调整eden和survivor的空间占比)</p>
<p><strong>发生在新生代的GC叫做Young GC或Minor GC,<br>发生在老年代的GC叫做Old GC或Major GC</strong></p>
<p>堆:<br><figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/堆内存分区.png" alt="堆内存分区" title="">
                </div>
                <div class="image-caption">堆内存分区</div>
            </figure></p>
<p><strong>PS:<br>FromSurvivor和ToSurvivor这两块内存空间并不是固定的，<br>在进行GC的时候，这两块内存会轮流替换使用。这部分内容参考GC部分。</strong></p>
<p><strong>PS:<br>有的文章说 Full GC与Major GC一样是属于对老年代的GC，<br>也有的文章说 Full GC 是对整个堆区的GC，所以这点需要各位同学自行分辨Full GC语义。<br>见: <a href="https://www.zhihu.com/question/41922036" target="_blank" rel="noopener">知乎讨论</a></strong></p>
<h4 id="方法区"><a href="#方法区" class="headerlink" title="方法区"></a>方法区</h4><p>方法区在JVM规范里也是各个<strong>线程共享的一部分区域，<br>它用于存储已被jvm加载的类的元信息，运行时常量池等数据。</strong></p>
<p>HotSpot虚拟机对于方法区的实现在jdk8之前为永久代，在jdk8之后，<br>HotSpot移除了永久代，新增了元空间。</p>
<p>元空间使用的是本地内存，所以元空间仅受本地物理内存的限制。<br>元空间存储着已被加载的类的方法描述，字段描述，运行时常量池等信息。</p>
<p><strong>字符串常量池在jdk7已经从永久代转移到了堆内存之中。</strong></p>
<p><strong>方法区在逻辑上是属于堆区的。在jdk8之前，堆区在GC时会回收永久代。<br>但jdk8之后的元空间归属于物理内存，存储的都是常量，几乎不会发生GC。</strong></p>
<p><strong>无论是永久代还是元空间，都有可能发生OOM。</strong></p>
<h3 id="JavaVirtualMachineError"><a href="#JavaVirtualMachineError" class="headerlink" title="JavaVirtualMachineError"></a>JavaVirtualMachineError</h3><h4 id="StackOverflowError"><a href="#StackOverflowError" class="headerlink" title="StackOverflowError"></a>StackOverflowError</h4><p>当前线程执行或请求的栈的大小超过了Java<br>虚拟机栈的最大空间(比如递归嵌套调用太深),就可能出现StackOverflowError错误</p>
<h4 id="OutOfMemoryError"><a href="#OutOfMemoryError" class="headerlink" title="OutOfMemoryError"></a>OutOfMemoryError</h4><p>发生OOM的情况: </p>
<ul>
<li><p>java heap space </p>
<blockquote>
<p>当需要为对象分配内存时，堆空间占用已经达到最大值，<br>无法继续为对象分配内存，可能会出现OOM: java heap space错误。 </p>
</blockquote>
</li>
<li><p>GC overhead limit exceed</p>
<blockquote>
<p>垃圾回收器花费了很长时间GC,但是GC回收的内存非常少,<br>就可能抛出OOM:GC overhead limit exceed 错误。</p>
<p>但是这点在我的机器上测试不出来,可能与jdk版本或gc收集器或Xmx分配内存的大小有关,<br>一直抛出的是java heap space</p>
</blockquote>
</li>
<li><p>Direct buffer memory</p>
<blockquote>
<p>当程序分配了超额的本地物理内存(native memory/ direct buffer)，<br>minor gc(young gc)并不会回收这部分内存，<br>只有 full gc才会回收直接内存，如果不发生full  gc，<br>但直接内存却被使用完了，那么可能会发生 OOM: Direct buffer memory。</p>
</blockquote>
</li>
<li><p>unable to create new native thread </p>
<blockquote>
<p>操作系统的线程资源是有限的，<br>如果程序创建的线程资源太多(无需超过平台限制的线程资源上限)，<br>就可能发生 OOM: unable to create new native thread 错误。 </p>
</blockquote>
</li>
<li><p>Metaspace</p>
<blockquote>
<p>当加载到元空间中的类的信息太多，就有可能导致 OOM : Metaspace。</p>
</blockquote>
</li>
</ul>
<p><strong>PS:<br>使用cglib的库，可以动态生成class，<br>所以可以使用cglib测试此错误(Metaspace)</strong></p>
<hr>
<h3 id="简单了解类文件结构"><a href="#简单了解类文件结构" class="headerlink" title="简单了解类文件结构"></a>简单了解类文件结构</h3><p>Class文件结构如下:</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/Class文件结构1.png" alt="Class文件结构1" title="">
                </div>
                <div class="image-caption">Class文件结构1</div>
            </figure>
<p>使用vim -b filename 以二进制模式编辑class文件，<br>然后输入 <strong>:%!xxd</strong> 即可查看十六进制的Class文件,如下:</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/Class文件结构2.png" alt="Class文件结构2" title="">
                </div>
                <div class="image-caption">Class文件结构2</div>
            </figure>
<p>当然，最直观的方法是对 class 文件使用 javap -c命令进行详细查看。</p>
<hr>
<h3 id="类的生命周期"><a href="#类的生命周期" class="headerlink" title="类的生命周期"></a>类的生命周期</h3><p>当java源代码文件被javac编译成class文件后，并不能直接运行，<br>而是需要经过加载，连接和初始化这几个阶段后才能使用。<br>在使用完类或JVM被销毁后，JVM会将类卸载掉。</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/类的生命周期.png" alt="类的生命周期" title="">
                </div>
                <div class="image-caption">类的生命周期</div>
            </figure>
<h4 id="类加载过程"><a href="#类加载过程" class="headerlink" title="类加载过程"></a>类加载过程</h4><p>类加载过程需要经过3个阶段:</p>
<ol>
<li>加载</li>
<li>连接</li>
<li>初始化</li>
</ol>
<p>其中连接又可分为3个阶段: 验证 ， 准备 ， 解析。</p>
<h4 id="加载"><a href="#加载" class="headerlink" title="加载"></a>加载</h4><p><strong>在加载阶段，类加载器将类的class文件的二进制数据读取到内存，<br>并保存到方法区，并在堆区生成该类的Class对象。</strong></p>
<p>通常有多种方式可以获取类的二进制数据:</p>
<ul>
<li>通过javac编译器编译java源文件，读取在本地磁盘上生成的class文件。</li>
<li>从Jar，ZIP等归档文件中读取class文件。</li>
<li>通过网络读取类的字节流。</li>
<li>通过动态生成字节码的技术(如使用动态代理，cglib)来生成class。</li>
</ul>
<p><strong>PS:数组由数组元素的类型的类加载器在java程序运行时加载，这是ClassLoader类的部分注释:</strong></p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/ClassLoader部分注释.png" alt="ClassLoader部分注释" title="">
                </div>
                <div class="image-caption">ClassLoader部分注释</div>
            </figure>
<p><strong>见: <a href="https://github.com/guang19/framework-learning/blob/master/jdk_jvm_juc-learning/src/main/java/com/github/guang19/jvm/classloader/ArrayClassLoaderTest.java" target="_blank" rel="noopener">测试</a></strong></p>
<h4 id="连接"><a href="#连接" class="headerlink" title="连接"></a>连接</h4><p>1.验证<br><strong>验证阶段是为了确保类的字节流符合虚拟机规范，并且不会对虚拟机造成恶意损害。</strong><br>JVM会对字节流进行如下验证:</p>
<ul>
<li><p>文件格式验证:会验证class文件是否符合虚拟机规范，如是否以0×CAFEBABE开头，<br>主次版本号是否在虚拟机规定范围类，常量池中的类型是否有JVM不支持的类型。</p>
</li>
<li><p>元数据验证: 会对类的元信息进行语义分析，确保符合Java语法规范。</p>
</li>
<li><p>字节码验证: 通过分析数据流和控制流，确保类的方法体的程序语义是合法的，<br>符合逻辑的。</p>
</li>
<li><p>符号引用验证: 确保常量池中的符号引用能在解析阶段正常解析。</p>
</li>
</ul>
<p>2.准备: 准备阶段会为类的静态变量初始化零值，如(0,0L,null,false).</p>
<p>3.解析: 解析阶段会将常量池中的符号引用转为直接引用。<br>符号引用包括类的全限定名，方法名和描述符，字段名和描述符。<br>直接引用是指向目标的指针，可以简单理解为目标的内存地址。</p>
<h4 id="初始化"><a href="#初始化" class="headerlink" title="初始化"></a>初始化</h4><blockquote>
<p>初始化阶段是类加载过程的最后一个阶段。</p>
</blockquote>
<p>在这个阶段,<strong>只有主动使用类才会初始化类，总共有8种情况会涉及到主动使用类。</strong></p>
<ol>
<li>当jvm执行new指令时会初始化类。即当程序创建一个类的实例对象。</li>
<li>当jvm执行getstatic指令时会初始化类。即程序访问类的静态变量(不是静态常量，常量归属于运行时常量池)。</li>
<li>当jvm执行putstatic指令时会初始化类。即程序给类的静态变量赋值。</li>
<li>当jvm执行invokestatic指令时会初始化类。即程序调用类的静态方法。</li>
<li>当使用反射主动调用这个类时,也会初始化类,如Class.forname(“…”),newInstance()等等。</li>
<li>当初始化一个子类的时候，会先初始化这个子类的所有父类，然后才会初始化这个子类。</li>
<li>当一个类是启动类时，即这个类拥有main方法，那么jvm会首先初始化这个类。</li>
<li>MethodHandle和VarHandle可以看作是轻量级的反射调用机制，而要想使用这2个调用，<br>就必须先使用findStatic/findStaticVarHandle来初始化要调用的类。</li>
</ol>
<p><strong>PS:见:<a href="https://github.com/guang19/framework-learning/blob/master/jdk_jvm_juc-learning/src/main/java/com/github/guang19/jvm/classloader/LoadClass.java" target="_blank" rel="noopener">测试</a></strong></p>
<h4 id="使用"><a href="#使用" class="headerlink" title="使用"></a>使用</h4><p>在类被初始化完成后，就可以使用类了。</p>
<h4 id="类的卸载"><a href="#类的卸载" class="headerlink" title="类的卸载"></a>类的卸载</h4><p>类被卸载(Class对象被GC掉)需要满足3个条件:</p>
<ol>
<li>该类的实例对象都已被GC，也就是说堆中不存在该类的实例对象。</li>
<li>该类没有在其它任何地方被使用。</li>
<li>加载该类的类加载器实例已被GC。</li>
</ol>
<p><strong>在JVM的生命周期中，被JVM自带的类加载器所加载的类是不会被卸载的。<br>而被我们自定义的类加载器所加载的类是可能会被卸载的。</strong></p>
<p>其实只要想通一点就好了，<strong>jdk自带的BootstrapClassLoader，<br>PlatformClassLoader和AppClassLoader负责加载jdk提供的类，<br>它们(类加载器)的实例肯定不会被回收，其中BootstrapClassLoader在java中更是不能被获取到。<br>而我们自定义的类加载器的实例是可以被GC掉的，<br>所以被我们自定义类加载器加载的类是可以被GC掉的。</strong></p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/类卸载.png" alt="类卸载" title="">
                </div>
                <div class="image-caption">类卸载</div>
            </figure>
<p><strong>PS:使用-XX:+TraceClassUnloading 或 -Xlog:class+unload=info可以打印类卸载的信息。</strong></p>
<h4 id="Java中类加载器有多少个"><a href="#Java中类加载器有多少个" class="headerlink" title="Java中类加载器有多少个"></a>Java中类加载器有多少个</h4><ol>
<li>BootstrapClassLoader(用于加载Java基础核心类库。由c/c++编写，Java获取不到)。</li>
<li>PlatformClassLoader<br>(jdk9之后才有此类加载器，jdk8之前是扩展加载器ExtensionClassLoader<br>。PlatformClassLoader加载平台相关的模块，ExtensionClassLoader加载jdk扩展的模块)。</li>
<li>AppClassLoader。(应用程序类加载器，负责加载我们程序的classpath下的jar和类)。</li>
<li>自定义类加载器。</li>
</ol>
<h4 id="类加载器的命名空间"><a href="#类加载器的命名空间" class="headerlink" title="类加载器的命名空间"></a>类加载器的命名空间</h4><p><strong>每个类加载器实例都有自己的命名空间，命名空间由该加载器及其所有父加载器加载的所有的类组成。</strong></p>
<ul>
<li><p>在同一个命名空间中(<strong>一个类加载器实例</strong>)，不会出现全限定名(包括包名)相同的2个类(<strong>不会加载2个相同名称的类</strong>)。</p>
</li>
<li><p>在不同的命名空间中(<strong>多个类加载器实例</strong>)，可能会出现全限定名(包括包名)相同的2个类(<strong>可能加载2个相同名称的类</strong>)。</p>
</li>
</ul>
<p><strong>PS:见:<a href="https://github.com/guang19/framework-learning/blob/master/jdk_jvm_juc-learning/src/main/java/com/github/guang19/jvm/classloader/MyClassLoader.java" target="_blank" rel="noopener">测试</a></strong></p>
<h4 id="双亲委派机制"><a href="#双亲委派机制" class="headerlink" title="双亲委派机制"></a>双亲委派机制</h4><h4 id="为什么需要双亲委派机制"><a href="#为什么需要双亲委派机制" class="headerlink" title="为什么需要双亲委派机制?"></a>为什么需要双亲委派机制?</h4><p><strong>双亲委派机制是为了防止类被重复加载，避免核心API遭到恶意破坏。</strong><br>如Object类，它由BootstrapClassLoader在JVM启动时加载。<br>如果没有双亲委派机制，那么Object类就可以被重写，其带来的后果将无法想象。</p>
<h4 id="双亲委派机制的实现原理"><a href="#双亲委派机制的实现原理" class="headerlink" title="双亲委派机制的实现原理?"></a>双亲委派机制的实现原理?</h4><p>每个类都有其对应的类加载器。</p>
<p>双亲委派机制是指在加载一个类的时候，JVM会判断这个类是否已经被其类加载器加载过了。<br>如果已经加载过了，那么直接返回这个类。<br><strong>如果没有加载，就使用这个类对应的加载器的父类加载器判断，<br>一层一层的往上判断，最终会由BootstrapClassLoader判断。</strong><br>如果BootstrapClassLoader判断都没有加载这个类,<br><strong>那么就由BootstrapClassLoader尝试加载。<br>如果BootstrapClassLoader加载失败了，<br>就由BootstrapClassLoader的子类加载器们加载。</strong></p>
<p><strong>在jdk9之后，由于模块化的到来，双亲委派机制也变化了一点:<br>如果类没有被加载，那么会根据类名找到这个类的模块。<br>如果找到了这个类的模块，<br>就由这个类的模块加载，否则仍然使用父类加载器加载。</strong></p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/双亲委派机制.png" alt="双亲委派机制" title="">
                </div>
                <div class="image-caption">双亲委派机制</div>
            </figure>
<p>可以看出:在加载一个类时，是由下自上判断类是否被加载的。如果类没有被加载，<br>就由上自下尝试加载类。</p>
<h3 id="JVM常量池"><a href="#JVM常量池" class="headerlink" title="JVM常量池"></a>JVM常量池</h3><p>Jvm常量池分为:</p>
<ol>
<li>Class常量池(静态常量池)</li>
<li>运行时常量池</li>
<li>字符串常量池(全局常量池)</li>
<li>包装类型缓存池</li>
</ol>
<h4 id="Class常量池-静态常量池"><a href="#Class常量池-静态常量池" class="headerlink" title="Class常量池(静态常量池)"></a>Class常量池(静态常量池)</h4><p>当Java源文件被编译后，就会生成Class字节码文件。</p>
<p><strong>Class常量池就存在于Class文件中(Class文件的Constant Pool中)。</strong></p>
<p><strong>Class文件常量池主要存放两大常量:字面量和符号引用。</strong></p>
<ol>
<li><p>字面量: 字面量分为文本字符串(如: “abc”,1等)和用final修饰的成员变量(实例变量和静态变量)</p>
</li>
<li><p>符号引用: 符号引用包括三种：类的全限定名，方法名和描述符，字段名和描述符。</p>
</li>
</ol>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/Class文件常量池.png" alt="Class文件常量池" title="">
                </div>
                <div class="image-caption">Class文件常量池</div>
            </figure>
<h4 id="运行时常量池"><a href="#运行时常量池" class="headerlink" title="运行时常量池"></a>运行时常量池</h4><p><strong>运行是常量池是在类加载阶段，将class二进制数据加载到内存，<br>并将数据保存到方法区,其中class文件中的常量池将保存到<br>运行时常量池(数据都在方法区，常量池肯定也在方法区)。<br>也就是说一个Class文件常量池对应一个运行时常量池。</strong></p>
<h4 id="字符串常量池-全局常量池"><a href="#字符串常量池-全局常量池" class="headerlink" title="字符串常量池(全局常量池)"></a>字符串常量池(全局常量池)</h4><p>字符串常量池在jdk7之前都是存于永久代(永久代)之中,jdk7以后存于<br>堆区之中。</p>
<h4 id="包装类型缓存池"><a href="#包装类型缓存池" class="headerlink" title="包装类型缓存池"></a>包装类型缓存池</h4><p>包装类缓存池并不是所有的包装类都有，并且缓存池缓存的是一定范围内的数据。<br>拥有包装类型缓存池的类有:Integer,Byte,Character,Long,Short，<br>而Float，Double，Boolean都不具有缓存池。</p>
<p><strong>包装类的缓存池缓存的范围基本都为: -128 - 127之间，<br>Character的缓存范围为 0 - 127。</strong></p>
<hr>
<h2 id="GC"><a href="#GC" class="headerlink" title="GC"></a>GC</h2><h3 id="判断对象存活的方法"><a href="#判断对象存活的方法" class="headerlink" title="判断对象存活的方法"></a>判断对象存活的方法</h3><p>在垃圾回收器对堆内存回收前，需要判断对象是否存活。</p>
<ul>
<li><p>引用计数算法: 给每个对象添加一个引用计数器,每当对象被引用,<br>对象的引用计数器就加1,当引用失效时,引用计数器就减1。<br>直到引用计数器为0,就代表对象不再被引用。</p>
</li>
<li><p>可达性算法: 通过GC ROOT的对象节点往下搜索,节点走过的路径被称为引用链。<br>如果一个对象不处于任何引用链,那么此对象是不可达的。</p>
</li>
</ul>
<h4 id="引用计数法缺点"><a href="#引用计数法缺点" class="headerlink" title="引用计数法缺点"></a>引用计数法缺点</h4><p>引用计数的主要缺陷是很难解决循环引用的问题:<br>也就是当2个对象互相引用的时候,除了彼此,<br>没有其他地方引用这2个对象,那么他们的引用计数都为1,就无法被回收。      </p>
<h4 id="什么是GC-Root"><a href="#什么是GC-Root" class="headerlink" title="什么是GC Root ?"></a>什么是GC Root ?</h4><p>上面说通过GC Root对象搜索引用链,那么GC Root对象是什么对象,<br>或者说什么样的对象是GC Root对象。<br>可以作为GC Root对象的有: </p>
<ol>
<li>虚拟机栈（栈帧中的局部变量区，也叫局部变量表）中应用的对象。</li>
<li>方法区中的类静态属性引用的对象</li>
<li>方法区中常量引用的对象</li>
<li>本地方法栈中JNI（native方法）引用的对象</li>
</ol>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/可达性算法.png" alt="可达性算法" title="">
                </div>
                <div class="image-caption">可达性算法</div>
            </figure>      
<h3 id="垃圾回收算法"><a href="#垃圾回收算法" class="headerlink" title="垃圾回收算法"></a>垃圾回收算法</h3><p>常见的垃圾回收算法主要有以下4种:</p>
<ol>
<li>复制算法</li>
<li>标记-清除算法</li>
<li>标记-整理算法</li>
<li>分代收集算法</li>
</ol>
<h4 id="复制算法-Copying"><a href="#复制算法-Copying" class="headerlink" title="复制算法(Copying)"></a>复制算法(Copying)</h4><p>将堆内存分为2块大小相等的内存空间，<br>每次只使用其中的一块内存，另一块则空闲。<br>当其中一块内存使用完后，<br>就将仍然存活的对象复制到另一块空闲内存空间，再清理已使用的内存。</p>
<p><strong>复制算法的优点是不会产生连续的内存碎片，速度也很高效。<br>但是缺点更明显:每次只使用内存的一半，就代表可使用的内存减少了1/2，代价很高昂。</strong></p>
<p><strong>复制算法一般用于新生代。<br>因为新生代的GC非常频繁，每次GC的对象较多，存活的对象较少。<br>所以采用复制算法效率更高，复制时只需要复制少量存活的对象。</strong></p>
<p><img src="/img/复制算法.png" alt="复制算法">         </p>
<h4 id="标记-清除算法-Mark-Sweep"><a href="#标记-清除算法-Mark-Sweep" class="headerlink" title="标记-清除算法(Mark-Sweep)"></a>标记-清除算法(Mark-Sweep)</h4><p>标记-清除算法分为2个步骤：标记和清除。</p>
<p>首先标记出所有可达(存活)的对象，在标记完成后，<br>统一回收所有未被标记(不可达)的对象。</p>
<p>标记-清除算法的缺点主要有2个:</p>
<ol>
<li><strong>标记和清除2个阶段的耗时都比较长，可以总结为效率较低。</strong></li>
<li><strong>对象在内存中的分布可能是不连续的，分散的，标记-清除后可能造成不连续的内存碎片。</strong><br>当内存碎片过多后，后续想要分配较大的对象时，无法找到足够大的内存碎片，<br>可能又需要触发GC。</li>
</ol>
<p><strong>标记-清除算法一般用于老年代。</strong><br>因为老年代中的对象存活率较高，几乎很少被回收，<br>所以标记-清除和标记-整理算法GC的时间不会太长，<br>GC的对象相比新生代更少。</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/标记-清除算法.png" alt="标记-清除算法" title="">
                </div>
                <div class="image-caption">标记-清除算法</div>
            </figure>
<h4 id="标记-整理算法-Mark-Compact"><a href="#标记-整理算法-Mark-Compact" class="headerlink" title="标记-整理算法(Mark-Compact)"></a>标记-整理算法(Mark-Compact)</h4><p>标记-整理算法是对标记-清除算法的一种改进。</p>
<p>标记-整理算法与标记-清除算法的在标记阶段是相同的，<br>都是首先标记出所有可达(存活)的对象。<br>但<strong>标记之后并不直接清理未被标记(不可达)的对象，<br>而是使被标记(存活)的对象向内存一端移动，然后清理掉这一端外的内存。</strong></p>
<p><strong>标记-整理算法的优点是:<br>几乎不会如标记-清除算法那样产生不连续的内存碎片。<br>但，所谓慢工出细活,标记-整理的效率是比标记-清除要低的。</strong>         </p>
<p><strong>标记-整理算法和标记-清除算法一样，一般用于老年代。</strong></p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/标记-整理算法.png" alt="标记-整理算法" title="">
                </div>
                <div class="image-caption">标记-整理算法</div>
            </figure>         
<h4 id="分代收集算法"><a href="#分代收集算法" class="headerlink" title="分代收集算法"></a>分代收集算法</h4><p><strong>分代收集算法并不是指某一种具体的垃圾收集算法，<br>而是将复制，标记-清除，标记-整理等算法合理运用到堆区的不同空间。</strong><br>比如新生代使用复制算法，老年代使用标记清除或标记整理算法。</p>
<p>现代的几乎所有的JVM都使用分代收集，毕竟每种算法都有优缺点，<br>结合它们的特点，对不同的环境采用不同的算法是非常明智的选择。</p>
<h4 id="内存分配与垃圾回收策略"><a href="#内存分配与垃圾回收策略" class="headerlink" title="内存分配与垃圾回收策略"></a>内存分配与垃圾回收策略</h4><ol>
<li>对象优先在eden区域被分配</li>
<li>大对象将直接进入老年代<br>(大对象是指需要大量连续的内存空间的对象，如长字符串，大数组等。)</li>
<li>长期存活的对象将进入老年代</li>
</ol>
<h4 id="一次GC的过程"><a href="#一次GC的过程" class="headerlink" title="一次GC的过程"></a>一次GC的过程</h4><p>对象优先在eden区被分配，当eden区内存不足时，<br>JVM发起Minor GC。Minor GC的范围包括eden和From Survivor:</p>
<p>首先JVM会根据可达性算法标记出所有存活的对象。</p>
<p>如果存活的对象中，有的对象的年龄已经达到晋升阈值<br>(阈值是动态计算的，可以通过-XX:MaxTenuringThreshold设置最大年龄阈值)，<br>那么将已经达到阈值的对象复制到老年代中。</p>
<p>如果To Survivor空间不足以存放剩余存活对象，<br>则直接将存活的对象提前复制到老年代。<br>如果老年代也没有足够的空间存放存活的对象，<br>那么将触发Full GC(GC整个堆，包括新生代和老年代)。</p>
<p>如果To Survivor可以存放存活的对象，<br>那么将对象复制到To Survivor空间，并清理eden和From Survivor。</p>
<p>此时From Survivor为空，<br>那么From Survivor就成为了下一次的To Survivor，<br>此时To Survivor存放着存活的对象，就成为了下一次的From Survivor。<br>这样From Survivor与To Survivor就是不断交替复制的使用。</p>
<p><strong>老年代的空间比新生代的空间要大，<br>所以老年代的Major GC要比Minor GC耗时更长。<br>根据垃圾回收器的不同，老年代的GC算法也不同。</strong></p>
<h4 id="动态年龄阈值"><a href="#动态年龄阈值" class="headerlink" title="动态年龄阈值"></a>动态年龄阈值</h4><p>JVM并不要求对象年龄一定要达到 MaxTenuringThreshold 才会<br>晋升到老年代，晋升的年龄阈值是动态计算的。￼￼￼￼￼<br>如果在Survivor中，某个相同年龄阶段的所有对象大小的总和<br>大于Survivor区域的一半，则大于等于这个年龄的所有对象<br>可以直接进入老年代，无需等到MaxTenuringThreshold。</p>
<h3 id="垃圾回收器"><a href="#垃圾回收器" class="headerlink" title="垃圾回收器"></a>垃圾回收器</h3><p><strong>如果说垃圾回收算法是JVM对GC算法的方法论，那么垃圾回收器就是对GC算法的实现。</strong></p>
<p>垃圾回收器主要分为以下几种收集器:</p>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/垃圾回收器分类.png" alt="垃圾回收器分类" title="">
                </div>
                <div class="image-caption">垃圾回收器分类</div>
            </figure>
<h4 id="Serial串行收集器"><a href="#Serial串行收集器" class="headerlink" title="Serial串行收集器"></a>Serial串行收集器</h4><p>Serial收集器为单线程环境设计,并只使用一个线程进行垃圾回收。<br>在回收时，会暂停用户线程,并不适用于并发环境。</p>
<p>Serial收集器在单线程环境中是很高效的,它没有多线程切换的消耗。     </p>
<p><strong>Serial收集器采用复制算法</strong></p>
<h4 id="Serial-Old-串行收集器-老年代版本"><a href="#Serial-Old-串行收集器-老年代版本" class="headerlink" title="Serial Old 串行收集器(老年代版本)"></a>Serial Old 串行收集器(老年代版本)</h4><p>它是 Serial收集器的老年代使用的GC收集器，同样是一个单线程的垃圾收集器。 </p>
<p><strong>Serial Old收集器采用的是标记-整理算法。</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br></pre></td><td class="code"><pre><span class="line">   </span><br><span class="line">/** 开启串行收集器使用 -XX:+UseSerialGC , </span><br><span class="line">  * 这样默认新生代使用 Serial 收集器,</span><br><span class="line">  * 老年代使用 Serial Old 收集器. </span><br><span class="line">  *</span><br><span class="line">  * 设置VM参数:</span><br><span class="line">  *</span><br><span class="line">  * -XX:+Xlogs:gc* 打印gc信息</span><br><span class="line">  * -XX:+PrintCommandLineFlags  打印java版本信息</span><br><span class="line">  * -XX:+UseSerialGC 使用串行GC</span><br><span class="line">  */                      </span><br><span class="line"></span><br><span class="line">//如果程序正常运行,日志会显示 :</span><br><span class="line">// 新生代的信息为:  def new generation.....</span><br><span class="line">// 老年代的信息为:  tenured generation.....</span><br><span class="line"></span><br><span class="line">````           </span><br><span class="line">            </span><br><span class="line">#### Parallel Scavenge 并行多线程收集器</span><br><span class="line">Parallel Scavenge是并行收集器，它使用多个垃圾回收线程一起工作,</span><br><span class="line">但是仍然会暂停用户线程。</span><br><span class="line"></span><br><span class="line">Parallel Scavenge与其它垃圾回收器不同的是它**更关注于达到可控制的吞吐量。**</span><br><span class="line"></span><br><span class="line">吞吐量是CPU运行用户应用程序代码的时间与CPU总消耗的时间的比值:</span><br><span class="line"></span><br><span class="line">```text</span><br><span class="line">吞吐量 = 应用程序代码运行时间 / (应用程序代码运行时间 + GC时间)</span><br><span class="line">```</span><br><span class="line"></span><br><span class="line">**Parallel Scavenge收集器采用复制算法**</span><br><span class="line"></span><br><span class="line">   </span><br><span class="line">#### Parallel Old 并行收集器(老年代版本)</span><br><span class="line"></span><br><span class="line">它是 Parallel Scavenge 的老年代版本,同样是一个并行多线程的收集器。</span><br><span class="line"></span><br><span class="line">**Parallel Old收集器采用标记-整理算法。**</span><br><span class="line">  </span><br><span class="line">````text</span><br><span class="line">    /**</span><br><span class="line">     * </span><br><span class="line">     * 设置 Parallel Scavenge 收集器的参数:</span><br><span class="line">     *</span><br><span class="line">     * -XX:+UseParallelGC</span><br><span class="line">     * </span><br><span class="line">     * ParallelGC老年代默认使用的 Parallel Old GC 回收器</span><br><span class="line">     * </span><br><span class="line">     * 并行收集器打印的新生代的信息为:</span><br><span class="line">     *  PSYoungGen ....</span><br><span class="line">     *  </span><br><span class="line">     *  老年代的信息为:</span><br><span class="line">     *  ParOldGen ....</span><br><span class="line">     * </span><br><span class="line">     */</span><br><span class="line">````        </span><br><span class="line">        </span><br><span class="line">        </span><br><span class="line">#### ParNew 多线程收集器</span><br><span class="line">它可以看做是多线程版的Serial收集器。</span><br><span class="line">除了多线程外，ParNew收集器与Serial收集器几乎没啥区别。</span><br><span class="line"></span><br><span class="line">**PS:目前只有Serial和ParNew能作为CMS收集器的新生代收集器。**</span><br><span class="line">         </span><br><span class="line">**ParNew收集器采用复制算法**</span><br><span class="line"></span><br><span class="line">````text</span><br><span class="line">     /**</span><br><span class="line">       * </span><br><span class="line">       * 设置ParNewGC回收器的参数为:</span><br><span class="line">       * -XX:+UseConcMarkSweepGC</span><br><span class="line">       * </span><br><span class="line">       */</span><br><span class="line">````           </span><br><span class="line">        </span><br><span class="line">#### CMS 并发标记清除收集器</span><br><span class="line">Concurrent Mark Sweep,并发标记-清除垃圾回收器。</span><br><span class="line">它是一款老年代的收集器，是**以达到最短回收停顿时间目标的收集器。**</span><br><span class="line"></span><br><span class="line">**见名知意,CMS收集器使用的是标记-清除算法。</span><br><span class="line">CMS在垃圾回收过程中，用户线程可以同时工作，无需暂停。**</span><br><span class="line"></span><br><span class="line">**因为CMS收集器采用的是标记-清除算法，所以回收时可能会产生不连续的内存碎片。**</span><br><span class="line"></span><br><span class="line">#### CMS收集器回收过程</span><br><span class="line"> </span><br><span class="line">- 初始标记(Stop The World，此阶段会暂停用户线程): 只标记与GC ROOT直接关联的对象。</span><br><span class="line"></span><br><span class="line">- 并发标记: 对第一个阶段已经标记的对象进行Tracing，标记所有可达的对象。</span><br><span class="line"></span><br><span class="line">- 重新标记(Stop The World,此阶段会暂停用户线程): 在第二个阶段，由于用户程序的运行，</span><br><span class="line">可能有些对象之间的引用关系受到了影响，所以需要对这部分对象进行重新标记调整。</span><br><span class="line"></span><br><span class="line">- 并发清除: 清除所有未被标记的对象。</span><br><span class="line">      </span><br><span class="line"> ````text</span><br><span class="line">    /**</span><br><span class="line">     *</span><br><span class="line">     * 设置 CMS 收集器参数:</span><br><span class="line">     * -XX:+UseConcMarkSweepGC</span><br><span class="line">     *</span><br><span class="line">     * 使用ConcMarkSweepGC收集器后,它的新生代使用的是:</span><br><span class="line">     * ParNew收集器.</span><br><span class="line">     *</span><br><span class="line">     * 当ConcMarkSweepGC收集器出现异常时,会将CMS替换成Serial Old收集器</span><br><span class="line">     *</span><br><span class="line">     * CMS回收分为4个阶段:</span><br><span class="line">     *</span><br><span class="line">     * 初始标记:    (Stop the world 暂停用户线程)</span><br><span class="line">     * 标记与GC Root直接可达的对象.      </span><br><span class="line">     *</span><br><span class="line">     * 并发标记:  </span><br><span class="line">     * 从第一步标记的可达的对象开始,并发的标记所有可达的对象 </span><br><span class="line">     *</span><br><span class="line">     * 重新标记:    (Stop the world 暂停用户线程)</span><br><span class="line">     * 在第二部的并发标记阶段,由于程序运行导致对象间引用的关系发生变化,</span><br><span class="line">     * 就需要重新标记</span><br><span class="line">     *</span><br><span class="line">     * 并发清除:     </span><br><span class="line">     * 这个阶段不暂停用户线程,并且并发的去清除未被标记的对象</span><br><span class="line">     * </span><br><span class="line">     */</span><br></pre></td></tr></table></figure>
<h4 id="G1-收集器"><a href="#G1-收集器" class="headerlink" title="G1 收集器"></a>G1 收集器</h4><p>G1收集器可以说是目前最前沿的一款收集器，它是一款面向服务端的收集器。</p>
<p>G1收集器<strong>无需配合其他收集器就可以管理整个堆内存。</strong><br>jdk9开始，G1成为jdk默认使用的垃圾回收器</p>
<h4 id="G1回收器的特点"><a href="#G1回收器的特点" class="headerlink" title="G1回收器的特点"></a>G1回收器的特点</h4><ul>
<li><p>并行和并发: G1能够充分利用多核cpu的优势，使垃圾回收与用户线程同时运行。</p>
</li>
<li><p>可预测的停顿: 降低GC停顿时间是CMS与G1收集器的共同目标。但是除了降低GC停顿时间，<br>G1收集器还可以建立可预测的停顿时间模型。(…太np了 =_=)</p>
</li>
<li><p>空间整合: 个人认为这是G1收集器不同于其他收集器的最大亮点了。<br>在其他收集器中，堆区基本都分为新生代和老年代。<br>而在G1收集器中虽然仍然保留了新生代和老年代的概念，但已经不再是物理上的分隔了。<br><strong>在G1收集器的堆内存模型中，内存被分割成了一块一块大小相等的Region，<br>在这些Region中，Region的类型也不同，有eden，survivor，old，humongous之分。<br>当有大对象时，对象会被分配到Humongous Region之中。</strong></p>
</li>
</ul>
<figure class="image-bubble">
                <div class="img-lightbox">
                    <div class="overlay"></div>
                    <img src="/img/G1收集器Region.png" alt="G1收集器Region" title="">
                </div>
                <div class="image-caption">G1收集器Region</div>
            </figure>
<h4 id="G1收集器回收过程"><a href="#G1收集器回收过程" class="headerlink" title="G1收集器回收过程"></a>G1收集器回收过程</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">G1收集器与CMS收集器的回收过程相似</span><br></pre></td></tr></table></figure>
<ul>
<li><p>初始标记(Stop The World,此阶段会暂停用户线程): 只标记与GC ROOT直接关联的对象。</p>
</li>
<li><p>并发标记: 对第一个阶段标记的对象Tracing，标记所有可达的对象。</p>
</li>
<li><p>最终标记(Stop The World,此阶段会暂停用户线程): 在并发标记阶段，由于用户线程执行，<br>可能导致被标记对象之间的引用关系发生影响，需要对这些对象进行重新标记调整。</p>
</li>
<li><p>筛选回收: 不同于CMS的并发清除，G1收集器首先会对所有Region的回收价值和回收成本进行排序,<br>然后再进行回收。这样可以在有限的时间内获得最大的回收率。</p>
</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br></pre></td><td class="code"><pre><span class="line">    /**</span><br><span class="line">     *</span><br><span class="line">     * 因为我的机器的jdk版本是11,所以无需指定垃圾回收器</span><br><span class="line">     * 指定G1回收器的参数是: -XX:+UseG1GC</span><br><span class="line">     *</span><br><span class="line">     * 1:初始标记:(Stop the world 暂停用户线程)</span><br><span class="line">     *   标记所有与GC Root直接可达的对象</span><br><span class="line">     *</span><br><span class="line">     * 2:并发标记</span><br><span class="line">     *  从第一个阶段标记的对象开始,trace标记</span><br><span class="line">     *</span><br><span class="line">     * 4:最终标记:(Stop the world 暂停用户线程)</span><br><span class="line">     *  在第二步并发标记的阶段,由于程序执行,</span><br><span class="line">     *  导致被标记对象之间的引用关系发生变化,所以需要重新调整标记</span><br><span class="line">     *</span><br><span class="line">     * 5:筛选回收:</span><br><span class="line">     *  和CMS的并发回收不一样,</span><br><span class="line">     *  G1收集器首先会对所有Region的回收价值和回收成本进行排序,</span><br><span class="line">     *  然后再进行回收。</span><br><span class="line">     *  这样可以保证在有限的时间内获得最大的回收率.</span><br><span class="line">     *</span><br><span class="line">     */</span><br><span class="line">```` </span><br><span class="line"></span><br><span class="line">---</span><br><span class="line"></span><br><span class="line">## JVM调优相关</span><br><span class="line"></span><br><span class="line">### JVM常见参数</span><br><span class="line"></span><br><span class="line">#### 堆栈相关</span><br><span class="line">* -Xss</span><br><span class="line">&gt;调整线程栈大小。</span><br><span class="line"></span><br><span class="line">* -Xms</span><br><span class="line">&gt;设置堆内存初始化大小。</span><br><span class="line"></span><br><span class="line">* -Xmx / -XX:MaxHeapSize=?</span><br><span class="line">&gt;设置堆内存最大值。</span><br><span class="line"></span><br><span class="line">* -Xmn / -XX:NewSize=?</span><br><span class="line">&gt;设置新生代大小。</span><br><span class="line"> </span><br><span class="line">* -XX:NewRatio=?</span><br><span class="line">&gt;设置老年代与新生代的空间占比。</span><br><span class="line">&gt;如: -XX:NewRatio=2,那么老年代:新生代=2:1。</span><br><span class="line"></span><br><span class="line">* -XX:SurvivorRatio=?</span><br><span class="line">&gt;设置eden与survivor的空间占比。</span><br><span class="line">&gt;如: -XX:SurvivorRatio=2,那么eden:from survivor:to survivor=2:1:1</span><br><span class="line"></span><br><span class="line">* -XX:MetaspaceSize=? / -XX:PerGenSize=?</span><br><span class="line">&gt;-XX:MetaspaceSize=9m</span><br><span class="line">&gt;设置元空间的初始化大小为9m,此参数只在jdk8以后的版本有效。</span><br><span class="line">&gt;</span><br><span class="line">&gt;-XX:PerGenSize=9m</span><br><span class="line">&gt;设置永久代的初始化大小为9m，此参数只在jdk8以前的版本有效。</span><br><span class="line"></span><br><span class="line">* -XX:MaxMetaspaceSize=? / -XX:MaxPerGenSize=?</span><br><span class="line">&gt;-XX:MaxMetaspaceSize=50m</span><br><span class="line">&gt;设置元空间最大值为50m,此参数只在jdk8以后的版本有效。</span><br><span class="line">&gt;</span><br><span class="line">&gt;-XX:MaxPerGenSize=50m</span><br><span class="line">&gt;设置永久代的最大值为50m,此参数只在jdk8以前的版本有效。</span><br><span class="line"></span><br><span class="line">* -XX:+HeapDumpOnOutOfMemoryError</span><br><span class="line">&gt;此参数使程序发生OOM时，dump错误堆栈信息。</span><br><span class="line"></span><br><span class="line">* -XX:HeapDumpPath=?</span><br><span class="line">&gt;-XX:HeapDumpPath=/home/log</span><br><span class="line">&gt;此参数指定发生OOM时，dump错误堆栈信息存放的日志文件或目录。</span><br><span class="line">&gt;此参数只在 -XX:+HeapDumpOnOutOfMemoryError 开启时生效。</span><br><span class="line"></span><br><span class="line">#### GC相关</span><br><span class="line">* -XX:+PrintGCDetails / -Xlog:gc*</span><br><span class="line">&gt;打印GC的日志信息。 -Xlog:gc* 在我使用的版本(jdk11)是更受推荐的。</span><br><span class="line"></span><br><span class="line">* -XX:+TraceClassUnloading / -Xlog:class+unload=info</span><br><span class="line">&gt;打印类卸载的日志信息。 -Xlog:class+unload=info 在我使用的版本(jdk11)是更受推荐的。</span><br><span class="line"></span><br><span class="line">* -XX:+UseSerialGC</span><br><span class="line">&gt;使用Serial串行回收器。</span><br><span class="line"></span><br><span class="line">* -XX:+UseParallelGC</span><br><span class="line">&gt;使用Parallel并行回收器。</span><br><span class="line"></span><br><span class="line">* -XX:ParallelGCThreads=?</span><br><span class="line">&gt;设置并行收集的线程数,如-XX:ParallelGCThreads=5。</span><br><span class="line"></span><br><span class="line">* -XX:+UseConcMarkSweepGC</span><br><span class="line">&gt;使用CMS收集器，它默认的新生代搜集器为ParNew。</span><br><span class="line">&gt;可以与参数: -XX:+UseSerialGC 一起使用，就替换掉了ParNew，</span><br><span class="line">&gt;使用Serial作为CMS的新生代收集器。</span><br><span class="line"></span><br><span class="line">* -XX:+UseG1GC</span><br><span class="line">&gt;使用G1收集器。</span><br><span class="line"></span><br><span class="line">* -XX:MaxTenuringThreshold=?</span><br><span class="line">&gt;设置新生代对象晋升到老年代的最大年龄阈值。</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">#### 其他</span><br><span class="line">* -server / -client</span><br><span class="line">&gt;-server:以服务端模式运行应用程序，server模式适用于服务端应用程序。</span><br><span class="line">&gt;JVM在此模式下，会对服务端运行效率做很大优化。</span><br><span class="line">&gt;</span><br><span class="line">&gt;-client:以客户端模式运行应用程序，client模式适用于客户端桌面程序(GUI)。</span><br><span class="line">&gt;JVM在此模式下，会对客户端运行做很大优化。</span><br><span class="line"></span><br><span class="line">### Java常用调优命令和工具</span><br><span class="line">* jps(个人认为非常重要)</span><br><span class="line">&gt;jps 命令类似于 linux的 ps 命令，不过ps命令是用于查看系统进程的，</span><br><span class="line">&gt;而jps用于查看当前系统运行的java进程。</span><br><span class="line">&gt;</span><br><span class="line">````text</span><br><span class="line">jps -q 只输出java进程id</span><br><span class="line">jps -l 输出java进程main函数的详细路径</span><br><span class="line">jps -v 输出java进程时指定的jvm参数</span><br><span class="line">jps -m 输出java进程执行时main函数的参数</span><br></pre></td></tr></table></figure>
<ul>
<li>jstat<blockquote>
<p>jstat用于查看java进程的运行状态.</p>
</blockquote>
</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">jstat -class pid    用于查看java进程类的情况</span><br><span class="line">jstat -compiler pid 用于查看java进程编译的情况</span><br><span class="line">jstat -gc pid       用于查看java进程gc的情况</span><br></pre></td></tr></table></figure>
<ul>
<li>jinfo<blockquote>
<p>jinfo 查看正在运行的java进程的jvm参数</p>
</blockquote>
</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">jinfo -flag MetaspaceSize pid  查看java进程的jvm的元空间大小</span><br><span class="line">jinfo -flag MaxHeapSize pid    查看java进程的jvm的最大堆的大小</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
<ul>
<li>jmap<blockquote>
<p>jmap 既可以dump java程序的快照，也可以查看对象的统计信息。</p>
</blockquote>
</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">jmap -heap pid               查看java进程堆的信息</span><br><span class="line">jmap -histo pid              查看java进程对象的信息</span><br><span class="line">jmap -dump:file=filename pid 生成java进程jvm的堆快照到指定文件</span><br></pre></td></tr></table></figure>
<ul>
<li>jstack<blockquote>
<p>jstack用于分析java线程栈信息</p>
</blockquote>
</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">jstack pid</span><br></pre></td></tr></table></figure>
<ul>
<li>jconsole<blockquote>
<p>jconsole 是jdk提供的对java程序进行分析的GUI界面工具。</p>
</blockquote>
</li>
</ul>
<hr>
<h2 id="Jdk新特性"><a href="#Jdk新特性" class="headerlink" title="Jdk新特性"></a>Jdk新特性</h2><h3 id="Jdk8新特性"><a href="#Jdk8新特性" class="headerlink" title="Jdk8新特性"></a>Jdk8新特性</h3><ul>
<li><p>Lambda / 方法引用</p>
</li>
<li><p>接口新增default方法</p>
</li>
<li><p>Stream API</p>
</li>
<li><p>Optional API</p>
</li>
<li><p>新的时间API(java.time强烈推荐使用)</p>
</li>
<li><p>内置Base64工具</p>
</li>
</ul>
<h3 id="Jdk9新特性"><a href="#Jdk9新特性" class="headerlink" title="Jdk9新特性"></a>Jdk9新特性</h3><ul>
<li><p>集合的工厂方法</p>
</li>
<li><p>接口新增private方法</p>
</li>
<li><p>响应式流(Doug Lea大师编写的，个人认为很重要，也是Webflux的基础吧)</p>
</li>
<li><p>JShell 交互式编程环境</p>
</li>
</ul>

        </div>

        <blockquote class="post-copyright">
    
    <div class="content">
        
<span class="post-time">
    最后更新时间：<time datetime="2020-04-13T09:28:05.045Z" itemprop="dateUpdated">2020-04-13 17:28:05</time>
</span><br>


        
    </div>
    
    <footer>
        <a href="http://springcloud.xn--ses554g">
            <img src="/img/123.png" alt="Edward">
            Edward
        </a>
    </footer>
</blockquote>

        


        <div class="post-footer">
            
	<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/java/">java</a></li></ul>


            
<div class="page-share-wrap">
    

<div class="page-share" id="pageShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://springcloud.xn--ses554g/2020/04/07/jdk_jvm_juc-learning/&title=《JUC和JVM》 — Edward&pic=http://springcloud.xn--ses554g/img/123.png" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://springcloud.xn--ses554g/2020/04/07/jdk_jvm_juc-learning/&title=《JUC和JVM》 — Edward&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://springcloud.xn--ses554g/2020/04/07/jdk_jvm_juc-learning/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《JUC和JVM》 — Edward&url=http://springcloud.xn--ses554g/2020/04/07/jdk_jvm_juc-learning/&via=http://springcloud.xn--ses554g" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://springcloud.xn--ses554g/2020/04/07/jdk_jvm_juc-learning/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>



    <a href="javascript:;" id="shareFab" class="page-share-fab waves-effect waves-circle">
        <i class="icon icon-share-alt icon-lg"></i>
    </a>
</div>



        </div>
    </div>

    
<nav class="post-nav flex-row flex-justify-between">
  
    <div class="waves-block waves-effect prev">
      <a href="/2020/04/13/JVM/" id="post-prev" class="post-nav-link">
        <div class="tips"><i class="icon icon-angle-left icon-lg icon-pr"></i> Prev</div>
        <h4 class="title">周阳-阳哥JVM部分</h4>
      </a>
    </div>
  

  
    <div class="waves-block waves-effect next">
      <a href="/2020/04/06/RabbitMQ可靠性投递二/" id="post-next" class="post-nav-link">
        <div class="tips">Next <i class="icon icon-angle-right icon-lg icon-pl"></i></div>
        <h4 class="title">RabbitMQ消息100%可靠性投递的解决方案实现(二)</h4>
      </a>
    </div>
  
</nav>



    











    <!-- Valine Comments -->
    <div class="comments vcomment" id="comments"></div>
    <script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
    <script src="//unpkg.com/valine@latest/dist/Valine.min.js"></script>
    <!-- Valine Comments script -->
    <script>
        var GUEST_INFO = ['nick','mail','link'];
        var guest_info = 'nick,mail,link'.split(',').filter(function(item){
          return GUEST_INFO.indexOf(item) > -1
        });
        new Valine({
            el: '#comments',
            notify: 'false' == 'true',
            verify: 'false' == 'true',
            appId: "NHOU6qcrdobSwD5wwUJJ31pQ-gzGzoHsz",
            appKey: "E0RJgPMPwkjfMBOA88EalSzJ",
            avatar: "mm",
            placeholder: "Just go go",
            guest_info: guest_info.length == 0 ? GUEST_INFO : guest_info,
            pageSize: "10"
        })
    </script>
    <!-- Valine Comments end -->







</article>



</div>

        <footer class="footer">
    <div class="top">
        <p>
    <span id="busuanzi_container_site_uv">
        站点总访客数：30<span id="busuanzi_value_site_uv"></span>
    </span>
    <span id="busuanzi_container_site_pv">
        站点总访问量：425<span id="busuanzi_value_site_pv"></span>
    </span>
</p>


        <p>
            
                <span><a href="/atom.xml" target="_blank" class="rss" title="rss"><i class="icon icon-lg icon-rss"></i></a></span>
            
            <span>博客内容遵循 <a rel="license" href="https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh">知识共享 署名 - 非商业性 - 相同方式共享 4.0 国际协议</a></span>
        </p>
    </div>
    <div class="bottom">
        <p><span>Edward &copy; 2017 - 2021</span>
            <span>
                
                Power by <a href="http://hexo.io/" target="_blank">Hexo</a> Theme <a href="https://github.com/yscoder/hexo-theme-indigo" target="_blank">indigo</a>
            </span>
        </p>
    </div>
</footer>

    </main>
    <div class="mask" id="mask"></div>
<a href="javascript:;" id="gotop" class="waves-effect waves-circle waves-light"><span class="icon icon-lg icon-chevron-up"></span></a>



<div class="global-share" id="globalShare">
    <ul class="reset share-icons">
      <li>
        <a class="weibo share-sns" target="_blank" href="http://service.weibo.com/share/share.php?url=http://springcloud.xn--ses554g/2020/04/07/jdk_jvm_juc-learning/&title=《JUC和JVM》 — Edward&pic=http://springcloud.xn--ses554g/img/123.png" data-title="微博">
          <i class="icon icon-weibo"></i>
        </a>
      </li>
      <li>
        <a class="weixin share-sns wxFab" href="javascript:;" data-title="微信">
          <i class="icon icon-weixin"></i>
        </a>
      </li>
      <li>
        <a class="qq share-sns" target="_blank" href="http://connect.qq.com/widget/shareqq/index.html?url=http://springcloud.xn--ses554g/2020/04/07/jdk_jvm_juc-learning/&title=《JUC和JVM》 — Edward&source=" data-title=" QQ">
          <i class="icon icon-qq"></i>
        </a>
      </li>
      <li>
        <a class="facebook share-sns" target="_blank" href="https://www.facebook.com/sharer/sharer.php?u=http://springcloud.xn--ses554g/2020/04/07/jdk_jvm_juc-learning/" data-title=" Facebook">
          <i class="icon icon-facebook"></i>
        </a>
      </li>
      <li>
        <a class="twitter share-sns" target="_blank" href="https://twitter.com/intent/tweet?text=《JUC和JVM》 — Edward&url=http://springcloud.xn--ses554g/2020/04/07/jdk_jvm_juc-learning/&via=http://springcloud.xn--ses554g" data-title=" Twitter">
          <i class="icon icon-twitter"></i>
        </a>
      </li>
      <li>
        <a class="google share-sns" target="_blank" href="https://plus.google.com/share?url=http://springcloud.xn--ses554g/2020/04/07/jdk_jvm_juc-learning/" data-title=" Google+">
          <i class="icon icon-google-plus"></i>
        </a>
      </li>
    </ul>
 </div>


<div class="page-modal wx-share" id="wxShare">
    <a class="close" href="javascript:;"><i class="icon icon-close"></i></a>
    <p>扫一扫，分享到微信</p>
    <img src="" alt="微信分享二维码">
</div>




    <script src="//cdn.bootcss.com/node-waves/0.7.4/waves.min.js"></script>
<script>
var BLOG = { ROOT: '/', SHARE: true, REWARD: false };


</script>

<script src="//unpkg.com/hexo-theme-material-indigo@latest/js/main.min.js"></script>


<div class="search-panel" id="search-panel">
    <ul class="search-result" id="search-result"></ul>
</div>
<template id="search-tpl">
<li class="item">
    <a href="{path}" class="waves-block waves-effect">
        <div class="title ellipsis" title="{title}">{title}</div>
        <div class="flex-row flex-middle">
            <div class="tags ellipsis">
                {tags}
            </div>
            <time class="flex-col time">{date}</time>
        </div>
    </a>
</li>
</template>

<script src="//unpkg.com/hexo-theme-material-indigo@latest/js/search.min.js" async></script>






<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>





<script src="/live2dw/lib/L2Dwidget.min.js?094cbace49a39548bed64abff5988b05"></script><script>L2Dwidget.init({"pluginRootPath":"live2dw/","pluginJsPath":"lib/","pluginModelPath":"assets/","tagMode":false,"log":false,"model":{"jsonPath":"/live2dw/assets/hijiki.model.json"},"display":{"position":"right","width":200,"height":400},"mobile":{"show":false}});</script></body>
</html>
